diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/CodeGen/CGDebugInfo.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/CodeGen/CGDebugInfo.cpp | 1612 |
1 files changed, 1206 insertions, 406 deletions
diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGDebugInfo.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGDebugInfo.cpp index 81c910f40bf8..0f3f684d61dc 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGDebugInfo.cpp @@ -18,6 +18,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" +#include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclFriend.h" @@ -25,6 +26,8 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/VTableBuilder.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" @@ -46,13 +49,16 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MD5.h" #include "llvm/Support/Path.h" +#include "llvm/Support/SHA1.h" +#include "llvm/Support/SHA256.h" #include "llvm/Support/TimeProfiler.h" +#include <optional> using namespace clang; using namespace clang::CodeGen; static uint32_t getTypeAlignIfRequired(const Type *Ty, const ASTContext &Ctx) { auto TI = Ctx.getTypeInfo(Ty); - return TI.AlignIsRequired ? TI.Align : 0; + return TI.isAlignRequired() ? TI.Align : 0; } static uint32_t getTypeAlignIfRequired(QualType Ty, const ASTContext &Ctx) { @@ -67,8 +73,6 @@ CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) : CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()), DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs), DBuilder(CGM.getModule()) { - for (const auto &KV : CGM.getCodeGenOpts().DebugPrefixMap) - DebugPrefixMap[KV.first] = KV.second; CreateCompileUnit(); } @@ -243,6 +247,12 @@ PrintingPolicy CGDebugInfo::getPrintingPolicy() const { PP.SplitTemplateClosers = true; } + PP.SuppressInlineNamespace = false; + PP.PrintCanonicalTypes = true; + PP.UsePreferredNames = false; + PP.AlwaysIncludeTypeForTemplateArgument = true; + PP.UseEnumerators = false; + // Apply -fdebug-prefix-map. PP.Callbacks = &PrintCB; return PP; @@ -335,39 +345,44 @@ StringRef CGDebugInfo::getClassName(const RecordDecl *RD) { return StringRef(); } -Optional<llvm::DIFile::ChecksumKind> -CGDebugInfo::computeChecksum(FileID FID, SmallString<32> &Checksum) const { +std::optional<llvm::DIFile::ChecksumKind> +CGDebugInfo::computeChecksum(FileID FID, SmallString<64> &Checksum) const { Checksum.clear(); if (!CGM.getCodeGenOpts().EmitCodeView && CGM.getCodeGenOpts().DwarfVersion < 5) - return None; + return std::nullopt; SourceManager &SM = CGM.getContext().getSourceManager(); - Optional<llvm::MemoryBufferRef> MemBuffer = SM.getBufferOrNone(FID); + std::optional<llvm::MemoryBufferRef> MemBuffer = SM.getBufferOrNone(FID); if (!MemBuffer) - return None; - - llvm::MD5 Hash; - llvm::MD5::MD5Result Result; - - Hash.update(MemBuffer->getBuffer()); - Hash.final(Result); - - Hash.stringifyResult(Result, Checksum); - return llvm::DIFile::CSK_MD5; + return std::nullopt; + + auto Data = llvm::arrayRefFromStringRef(MemBuffer->getBuffer()); + switch (CGM.getCodeGenOpts().getDebugSrcHash()) { + case clang::CodeGenOptions::DSH_MD5: + llvm::toHex(llvm::MD5::hash(Data), /*LowerCase=*/true, Checksum); + return llvm::DIFile::CSK_MD5; + case clang::CodeGenOptions::DSH_SHA1: + llvm::toHex(llvm::SHA1::hash(Data), /*LowerCase=*/true, Checksum); + return llvm::DIFile::CSK_SHA1; + case clang::CodeGenOptions::DSH_SHA256: + llvm::toHex(llvm::SHA256::hash(Data), /*LowerCase=*/true, Checksum); + return llvm::DIFile::CSK_SHA256; + } + llvm_unreachable("Unhandled DebugSrcHashKind enum"); } -Optional<StringRef> CGDebugInfo::getSource(const SourceManager &SM, - FileID FID) { +std::optional<StringRef> CGDebugInfo::getSource(const SourceManager &SM, + FileID FID) { if (!CGM.getCodeGenOpts().EmbedSource) - return None; + return std::nullopt; bool SourceInvalid = false; StringRef Source = SM.getBufferData(FID, &SourceInvalid); if (SourceInvalid) - return None; + return std::nullopt; return Source; } @@ -376,16 +391,18 @@ llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) { SourceManager &SM = CGM.getContext().getSourceManager(); StringRef FileName; FileID FID; + std::optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo; if (Loc.isInvalid()) { // The DIFile used by the CU is distinct from the main source file. Call // createFile() below for canonicalization if the source file was specified // with an absolute path. FileName = TheCU->getFile()->getFilename(); + CSInfo = TheCU->getFile()->getChecksum(); } else { PresumedLoc PLoc = SM.getPresumedLoc(Loc); FileName = PLoc.getFilename(); - + if (FileName.empty()) { FileName = TheCU->getFile()->getFilename(); } else { @@ -402,19 +419,21 @@ llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) { return cast<llvm::DIFile>(V); } - SmallString<32> Checksum; - - Optional<llvm::DIFile::ChecksumKind> CSKind = computeChecksum(FID, Checksum); - Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo; - if (CSKind) - CSInfo.emplace(*CSKind, Checksum); + // Put Checksum at a scope where it will persist past the createFile call. + SmallString<64> Checksum; + if (!CSInfo) { + std::optional<llvm::DIFile::ChecksumKind> CSKind = + computeChecksum(FID, Checksum); + if (CSKind) + CSInfo.emplace(*CSKind, Checksum); + } return createFile(FileName, CSInfo, getSource(SM, SM.getFileID(Loc))); } -llvm::DIFile * -CGDebugInfo::createFile(StringRef FileName, - Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo, - Optional<StringRef> Source) { +llvm::DIFile *CGDebugInfo::createFile( + StringRef FileName, + std::optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo, + std::optional<StringRef> Source) { StringRef Dir; StringRef File; std::string RemappedFile = remapDIPath(FileName); @@ -422,16 +441,16 @@ CGDebugInfo::createFile(StringRef FileName, SmallString<128> DirBuf; SmallString<128> FileBuf; if (llvm::sys::path::is_absolute(RemappedFile)) { - // Strip the common prefix (if it is more than just "/") from current - // directory and FileName for a more space-efficient encoding. + // Strip the common prefix (if it is more than just "/" or "C:\") from + // current directory and FileName for a more space-efficient encoding. auto FileIt = llvm::sys::path::begin(RemappedFile); auto FileE = llvm::sys::path::end(RemappedFile); auto CurDirIt = llvm::sys::path::begin(CurDir); auto CurDirE = llvm::sys::path::end(CurDir); for (; CurDirIt != CurDirE && *CurDirIt == *FileIt; ++CurDirIt, ++FileIt) llvm::sys::path::append(DirBuf, *CurDirIt); - if (std::distance(llvm::sys::path::begin(CurDir), CurDirIt) == 1) { - // Don't strip the common prefix if it is only the root "/" + if (llvm::sys::path::root_path(DirBuf) == DirBuf) { + // Don't strip the common prefix if it is only the root ("/" or "C:\") // since that would make LLVM diagnostic locations confusing. Dir = {}; File = RemappedFile; @@ -442,7 +461,8 @@ CGDebugInfo::createFile(StringRef FileName, File = FileBuf; } } else { - Dir = CurDir; + if (!llvm::sys::path::is_absolute(FileName)) + Dir = CurDir; File = RemappedFile; } llvm::DIFile *F = DBuilder.createFile(File, Dir, CSInfo, Source); @@ -451,12 +471,9 @@ CGDebugInfo::createFile(StringRef FileName, } std::string CGDebugInfo::remapDIPath(StringRef Path) const { - if (DebugPrefixMap.empty()) - return Path.str(); - SmallString<256> P = Path; - for (const auto &Entry : DebugPrefixMap) - if (llvm::sys::path::replace_path_prefix(P, Entry.first, Entry.second)) + for (auto &[From, To] : llvm::reverse(CGM.getCodeGenOpts().DebugPrefixMap)) + if (llvm::sys::path::replace_path_prefix(P, From, To)) break; return P.str().str(); } @@ -487,15 +504,17 @@ StringRef CGDebugInfo::getCurrentDirname() { if (!CWDName.empty()) return CWDName; - SmallString<256> CWD; - llvm::sys::fs::current_path(CWD); - return CWDName = internString(CWD); + llvm::ErrorOr<std::string> CWD = + CGM.getFileSystem()->getCurrentWorkingDirectory(); + if (!CWD) + return StringRef(); + return CWDName = internString(*CWD); } void CGDebugInfo::CreateCompileUnit() { - SmallString<32> Checksum; - Optional<llvm::DIFile::ChecksumKind> CSKind; - Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo; + SmallString<64> Checksum; + std::optional<llvm::DIFile::ChecksumKind> CSKind; + std::optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo; // Should we be asking the SourceManager for the main file name, instead of // accepting it as an argument? This just causes the main file name to @@ -506,7 +525,9 @@ void CGDebugInfo::CreateCompileUnit() { // Get absolute path name. SourceManager &SM = CGM.getContext().getSourceManager(); - std::string MainFileName = CGM.getCodeGenOpts().MainFileName; + auto &CGO = CGM.getCodeGenOpts(); + const LangOptions &LO = CGM.getLangOpts(); + std::string MainFileName = CGO.MainFileName; if (MainFileName.empty()) MainFileName = "<stdin>"; @@ -515,37 +536,45 @@ void CGDebugInfo::CreateCompileUnit() { // a relative path, so we look into the actual file entry for the main // file to determine the real absolute path for the file. std::string MainFileDir; - if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { - MainFileDir = std::string(MainFile->getDir()->getName()); + if (OptionalFileEntryRef MainFile = + SM.getFileEntryRefForID(SM.getMainFileID())) { + MainFileDir = std::string(MainFile->getDir().getName()); if (!llvm::sys::path::is_absolute(MainFileName)) { llvm::SmallString<1024> MainFileDirSS(MainFileDir); - llvm::sys::path::append(MainFileDirSS, MainFileName); - MainFileName = - std::string(llvm::sys::path::remove_leading_dotslash(MainFileDirSS)); + llvm::sys::path::Style Style = + LO.UseTargetPathSeparator + ? (CGM.getTarget().getTriple().isOSWindows() + ? llvm::sys::path::Style::windows_backslash + : llvm::sys::path::Style::posix) + : llvm::sys::path::Style::native; + llvm::sys::path::append(MainFileDirSS, Style, MainFileName); + MainFileName = std::string( + llvm::sys::path::remove_leading_dotslash(MainFileDirSS, Style)); } // If the main file name provided is identical to the input file name, and // if the input file is a preprocessed source, use the module name for // debug info. The module name comes from the name specified in the first - // linemarker if the input is a preprocessed source. + // linemarker if the input is a preprocessed source. In this case we don't + // know the content to compute a checksum. if (MainFile->getName() == MainFileName && FrontendOptions::getInputKindForExtension( MainFile->getName().rsplit('.').second) - .isPreprocessed()) + .isPreprocessed()) { MainFileName = CGM.getModule().getName().str(); - - CSKind = computeChecksum(SM.getMainFileID(), Checksum); + } else { + CSKind = computeChecksum(SM.getMainFileID(), Checksum); + } } llvm::dwarf::SourceLanguage LangTag; - const LangOptions &LO = CGM.getLangOpts(); if (LO.CPlusPlus) { if (LO.ObjC) LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus; - else if (LO.CPlusPlus14 && (!CGM.getCodeGenOpts().DebugStrictDwarf || - CGM.getCodeGenOpts().DwarfVersion >= 5)) + else if (CGO.DebugStrictDwarf && CGO.DwarfVersion < 5) + LangTag = llvm::dwarf::DW_LANG_C_plus_plus; + else if (LO.CPlusPlus14) LangTag = llvm::dwarf::DW_LANG_C_plus_plus_14; - else if (LO.CPlusPlus11 && (!CGM.getCodeGenOpts().DebugStrictDwarf || - CGM.getCodeGenOpts().DwarfVersion >= 5)) + else if (LO.CPlusPlus11) LangTag = llvm::dwarf::DW_LANG_C_plus_plus_11; else LangTag = llvm::dwarf::DW_LANG_C_plus_plus; @@ -556,6 +585,8 @@ void CGDebugInfo::CreateCompileUnit() { LangTag = llvm::dwarf::DW_LANG_OpenCL; } else if (LO.RenderScript) { LangTag = llvm::dwarf::DW_LANG_GOOGLE_RenderScript; + } else if (LO.C11 && !(CGO.DebugStrictDwarf && CGO.DwarfVersion < 5)) { + LangTag = llvm::dwarf::DW_LANG_C11; } else if (LO.C99) { LangTag = llvm::dwarf::DW_LANG_C99; } else { @@ -571,20 +602,20 @@ void CGDebugInfo::CreateCompileUnit() { llvm::DICompileUnit::DebugEmissionKind EmissionKind; switch (DebugKind) { - case codegenoptions::NoDebugInfo: - case codegenoptions::LocTrackingOnly: + case llvm::codegenoptions::NoDebugInfo: + case llvm::codegenoptions::LocTrackingOnly: EmissionKind = llvm::DICompileUnit::NoDebug; break; - case codegenoptions::DebugLineTablesOnly: + case llvm::codegenoptions::DebugLineTablesOnly: EmissionKind = llvm::DICompileUnit::LineTablesOnly; break; - case codegenoptions::DebugDirectivesOnly: + case llvm::codegenoptions::DebugDirectivesOnly: EmissionKind = llvm::DICompileUnit::DebugDirectivesOnly; break; - case codegenoptions::DebugInfoConstructor: - case codegenoptions::LimitedDebugInfo: - case codegenoptions::FullDebugInfo: - case codegenoptions::UnusedTypeInfo: + case llvm::codegenoptions::DebugInfoConstructor: + case llvm::codegenoptions::LimitedDebugInfo: + case llvm::codegenoptions::FullDebugInfo: + case llvm::codegenoptions::UnusedTypeInfo: EmissionKind = llvm::DICompileUnit::FullDebug; break; } @@ -606,22 +637,27 @@ void CGDebugInfo::CreateCompileUnit() { 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"); }); + auto It = + std::find_if(B, E, [](auto SDK) { return SDK.ends_with(".sdk"); }); if (It != E) SDK = *It; } + llvm::DICompileUnit::DebugNameTableKind NameTableKind = + static_cast<llvm::DICompileUnit::DebugNameTableKind>( + CGOpts.DebugNameTable); + if (CGM.getTarget().getTriple().isNVPTX()) + NameTableKind = llvm::DICompileUnit::DebugNameTableKind::None; + else if (CGM.getTarget().getTriple().getVendor() == llvm::Triple::Apple) + NameTableKind = llvm::DICompileUnit::DebugNameTableKind::Apple; + // Create new compile unit. TheCU = DBuilder.createCompileUnit( LangTag, CUFile, CGOpts.EmitVersionIdentMetadata ? Producer : "", LO.Optimize || CGOpts.PrepareForLTO || CGOpts.PrepareForThinLTO, CGOpts.DwarfDebugFlags, RuntimeVers, CGOpts.SplitDwarfFile, EmissionKind, DwoId, CGOpts.SplitDwarfInlining, CGOpts.DebugInfoForProfiling, - CGM.getTarget().getTriple().isNVPTX() - ? llvm::DICompileUnit::DebugNameTableKind::None - : static_cast<llvm::DICompileUnit::DebugNameTableKind>( - CGOpts.DebugNameTable), - CGOpts.DebugRangesBaseAddress, remapDIPath(Sysroot), SDK); + NameTableKind, CGOpts.DebugRangesBaseAddress, remapDIPath(Sysroot), SDK); } llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { @@ -703,24 +739,41 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { #include "clang/Basic/AArch64SVEACLETypes.def" { ASTContext::BuiltinVectorTypeInfo Info = - CGM.getContext().getBuiltinVectorTypeInfo(BT); - unsigned NumElemsPerVG = (Info.EC.getKnownMinValue() * Info.NumVectors) / 2; + // For svcount_t, only the lower 2 bytes are relevant. + BT->getKind() == BuiltinType::SveCount + ? ASTContext::BuiltinVectorTypeInfo( + CGM.getContext().BoolTy, llvm::ElementCount::getFixed(16), + 1) + : CGM.getContext().getBuiltinVectorTypeInfo(BT); + + // A single vector of bytes may not suffice as the representation of + // svcount_t tuples because of the gap between the active 16bits of + // successive tuple members. Currently no such tuples are defined for + // svcount_t, so assert that NumVectors is 1. + assert((BT->getKind() != BuiltinType::SveCount || Info.NumVectors == 1) && + "Unsupported number of vectors for svcount_t"); // Debuggers can't extract 1bit from a vector, so will display a - // bitpattern for svbool_t instead. + // bitpattern for predicates instead. + unsigned NumElems = Info.EC.getKnownMinValue() * Info.NumVectors; if (Info.ElementType == CGM.getContext().BoolTy) { - NumElemsPerVG /= 8; + NumElems /= 8; Info.ElementType = CGM.getContext().UnsignedCharTy; } - auto *LowerBound = - llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned( - llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0)); - SmallVector<int64_t, 9> Expr( - {llvm::dwarf::DW_OP_constu, NumElemsPerVG, llvm::dwarf::DW_OP_bregx, - /* AArch64::VG */ 46, 0, llvm::dwarf::DW_OP_mul, - llvm::dwarf::DW_OP_constu, 1, llvm::dwarf::DW_OP_minus}); - auto *UpperBound = DBuilder.createExpression(Expr); + llvm::Metadata *LowerBound, *UpperBound; + LowerBound = llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned( + llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0)); + if (Info.EC.isScalable()) { + unsigned NumElemsPerVG = NumElems / 2; + SmallVector<uint64_t, 9> Expr( + {llvm::dwarf::DW_OP_constu, NumElemsPerVG, llvm::dwarf::DW_OP_bregx, + /* AArch64::VG */ 46, 0, llvm::dwarf::DW_OP_mul, + llvm::dwarf::DW_OP_constu, 1, llvm::dwarf::DW_OP_minus}); + UpperBound = DBuilder.createExpression(Expr); + } else + UpperBound = llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned( + llvm::Type::getInt64Ty(CGM.getLLVMContext()), NumElems - 1)); llvm::Metadata *Subscript = DBuilder.getOrCreateSubrange( /*count*/ nullptr, LowerBound, UpperBound, /*stride*/ nullptr); @@ -762,7 +815,7 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { } // Element count = (VLENB / SEW) x LMUL - SmallVector<int64_t, 9> Expr( + SmallVector<uint64_t, 12> Expr( // The DW_OP_bregx operation has two operands: a register which is // specified by an unsigned LEB128 number, followed by a signed LEB128 // offset. @@ -776,6 +829,8 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { Expr.push_back(llvm::dwarf::DW_OP_div); else Expr.push_back(llvm::dwarf::DW_OP_mul); + // Element max index = count - 1 + Expr.append({llvm::dwarf::DW_OP_constu, 1, llvm::dwarf::DW_OP_minus}); auto *LowerBound = llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned( @@ -791,6 +846,17 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { return DBuilder.createVectorType(/*Size=*/0, Align, ElemTy, SubscriptArray); } + +#define WASM_REF_TYPE(Name, MangledName, Id, SingletonId, AS) \ + case BuiltinType::Id: { \ + if (!SingletonId) \ + SingletonId = \ + DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, \ + MangledName, TheCU, TheCU->getFile(), 0); \ + return SingletonId; \ + } +#include "clang/Basic/WebAssemblyReferenceTypes.def" + case BuiltinType::UChar: case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; @@ -830,11 +896,12 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { case BuiltinType::BFloat16: case BuiltinType::Float128: case BuiltinType::Double: - // FIXME: For targets where long double and __float128 have the same size, - // they are currently indistinguishable in the debugger without some - // special treatment. However, there is currently no consensus on encoding - // and this should be updated once a DWARF encoding exists for distinct - // floating point types of the same size. + case BuiltinType::Ibm128: + // FIXME: For targets where long double, __ibm128 and __float128 have the + // same size, they are currently indistinguishable in the debugger without + // some special treatment. However, there is currently no consensus on + // encoding and this should be updated once a DWARF encoding exists for + // distinct floating point types of the same size. Encoding = llvm::dwarf::DW_ATE_float; break; case BuiltinType::ShortAccum: @@ -867,35 +934,15 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { break; } - switch (BT->getKind()) { - case BuiltinType::Long: - BTName = "long int"; - break; - case BuiltinType::LongLong: - BTName = "long long int"; - break; - case BuiltinType::ULong: - BTName = "long unsigned int"; - break; - case BuiltinType::ULongLong: - BTName = "long long unsigned int"; - break; - default: - BTName = BT->getName(CGM.getLangOpts()); - break; - } + BTName = BT->getName(CGM.getLangOpts()); // Bit size and offset of the type. uint64_t Size = CGM.getContext().getTypeSize(BT); return DBuilder.createBasicType(BTName, Size, Encoding); } -llvm::DIType *CGDebugInfo::CreateType(const AutoType *Ty) { - return DBuilder.createUnspecifiedType("auto"); -} +llvm::DIType *CGDebugInfo::CreateType(const BitIntType *Ty) { -llvm::DIType *CGDebugInfo::CreateType(const ExtIntType *Ty) { - - StringRef Name = Ty->isUnsigned() ? "unsigned _ExtInt" : "_ExtInt"; + StringRef Name = Ty->isUnsigned() ? "unsigned _BitInt" : "_BitInt"; llvm::dwarf::TypeKind Encoding = Ty->isUnsigned() ? llvm::dwarf::DW_ATE_unsigned : llvm::dwarf::DW_ATE_signed; @@ -914,29 +961,41 @@ llvm::DIType *CGDebugInfo::CreateType(const ComplexType *Ty) { return DBuilder.createBasicType("complex", Size, Encoding); } +static void stripUnusedQualifiers(Qualifiers &Q) { + // Ignore these qualifiers for now. + Q.removeObjCGCAttr(); + Q.removeAddressSpace(); + Q.removeObjCLifetime(); + Q.removeUnaligned(); +} + +static llvm::dwarf::Tag getNextQualifier(Qualifiers &Q) { + if (Q.hasConst()) { + Q.removeConst(); + return llvm::dwarf::DW_TAG_const_type; + } + if (Q.hasVolatile()) { + Q.removeVolatile(); + return llvm::dwarf::DW_TAG_volatile_type; + } + if (Q.hasRestrict()) { + Q.removeRestrict(); + return llvm::dwarf::DW_TAG_restrict_type; + } + return (llvm::dwarf::Tag)0; +} + llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile *Unit) { QualifierCollector Qc; const Type *T = Qc.strip(Ty); - // Ignore these qualifiers for now. - Qc.removeObjCGCAttr(); - Qc.removeAddressSpace(); - Qc.removeObjCLifetime(); + stripUnusedQualifiers(Qc); // We will create one Derived type for one qualifier and recurse to handle any // additional ones. - llvm::dwarf::Tag Tag; - if (Qc.hasConst()) { - Tag = llvm::dwarf::DW_TAG_const_type; - Qc.removeConst(); - } else if (Qc.hasVolatile()) { - Tag = llvm::dwarf::DW_TAG_volatile_type; - Qc.removeVolatile(); - } else if (Qc.hasRestrict()) { - Tag = llvm::dwarf::DW_TAG_restrict_type; - Qc.removeRestrict(); - } else { + llvm::dwarf::Tag Tag = getNextQualifier(Qc); + if (!Tag) { assert(Qc.empty() && "Unknown type qualifier for debug info"); return getOrCreateType(QualType(T, 0), Unit); } @@ -948,6 +1007,30 @@ llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, return DBuilder.createQualifiedType(Tag, FromTy); } +llvm::DIType *CGDebugInfo::CreateQualifiedType(const FunctionProtoType *F, + llvm::DIFile *Unit) { + FunctionProtoType::ExtProtoInfo EPI = F->getExtProtoInfo(); + Qualifiers &Q = EPI.TypeQuals; + stripUnusedQualifiers(Q); + + // We will create one Derived type for one qualifier and recurse to handle any + // additional ones. + llvm::dwarf::Tag Tag = getNextQualifier(Q); + if (!Tag) { + assert(Q.empty() && "Unknown type qualifier for debug info"); + return nullptr; + } + + auto *FromTy = + getOrCreateType(CGM.getContext().getFunctionType(F->getReturnType(), + F->getParamTypes(), EPI), + Unit); + + // No need to fill in the Name, Line, Size, Alignment, Offset in case of + // CVR derived types. + return DBuilder.createQualifiedType(Tag, FromTy); +} + llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, llvm::DIFile *Unit) { @@ -1107,13 +1190,30 @@ llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag, QualType PointeeTy, llvm::DIFile *Unit) { // Bit size, align and offset of the type. - // Size is always the size of a pointer. We can't use getTypeSize here - // because that does not return the correct value for references. - unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(PointeeTy); - uint64_t Size = CGM.getTarget().getPointerWidth(AddressSpace); + // Size is always the size of a pointer. + uint64_t Size = CGM.getContext().getTypeSize(Ty); auto Align = getTypeAlignIfRequired(Ty, CGM.getContext()); - Optional<unsigned> DWARFAddressSpace = - CGM.getTarget().getDWARFAddressSpace(AddressSpace); + std::optional<unsigned> DWARFAddressSpace = + CGM.getTarget().getDWARFAddressSpace( + CGM.getTypes().getTargetAddressSpace(PointeeTy)); + + SmallVector<llvm::Metadata *, 4> Annots; + auto *BTFAttrTy = dyn_cast<BTFTagAttributedType>(PointeeTy); + while (BTFAttrTy) { + StringRef Tag = BTFAttrTy->getAttr()->getBTFTypeTag(); + if (!Tag.empty()) { + llvm::Metadata *Ops[2] = { + llvm::MDString::get(CGM.getLLVMContext(), StringRef("btf_type_tag")), + llvm::MDString::get(CGM.getLLVMContext(), Tag)}; + Annots.insert(Annots.begin(), + llvm::MDNode::get(CGM.getLLVMContext(), Ops)); + } + BTFAttrTy = dyn_cast<BTFTagAttributedType>(BTFAttrTy->getWrappedType()); + } + + llvm::DINodeArray Annotations = nullptr; + if (Annots.size() > 0) + Annotations = DBuilder.getOrCreateArray(Annots); if (Tag == llvm::dwarf::DW_TAG_reference_type || Tag == llvm::dwarf::DW_TAG_rvalue_reference_type) @@ -1121,7 +1221,8 @@ llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag, Size, Align, DWARFAddressSpace); else return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size, - Align, DWARFAddressSpace); + Align, DWARFAddressSpace, StringRef(), + Annotations); } llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name, @@ -1217,17 +1318,31 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, assert(Ty->isTypeAlias()); llvm::DIType *Src = getOrCreateType(Ty->getAliasedType(), Unit); - auto *AliasDecl = - cast<TypeAliasTemplateDecl>(Ty->getTemplateName().getAsTemplateDecl()) - ->getTemplatedDecl(); + const TemplateDecl *TD = Ty->getTemplateName().getAsTemplateDecl(); + if (isa<BuiltinTemplateDecl>(TD)) + return Src; + const auto *AliasDecl = cast<TypeAliasTemplateDecl>(TD)->getTemplatedDecl(); if (AliasDecl->hasAttr<NoDebugAttr>()) return Src; SmallString<128> NS; llvm::raw_svector_ostream OS(NS); - Ty->getTemplateName().print(OS, getPrintingPolicy(), /*qualified*/ false); - printTemplateArgumentList(OS, Ty->template_arguments(), getPrintingPolicy()); + + auto PP = getPrintingPolicy(); + Ty->getTemplateName().print(OS, PP, TemplateName::Qualified::None); + + // Disable PrintCanonicalTypes here because we want + // the DW_AT_name to benefit from the TypePrinter's ability + // to skip defaulted template arguments. + // + // FIXME: Once -gsimple-template-names is enabled by default + // and we attach template parameters to alias template DIEs + // we don't need to worry about customizing the PrintingPolicy + // here anymore. + PP.PrintCanonicalTypes = false; + printTemplateArgumentList(OS, Ty->template_arguments(), PP, + TD->getTemplateParameters()); SourceLocation Loc = AliasDecl->getLocation(); return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc), @@ -1235,6 +1350,33 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, getDeclContextDescriptor(AliasDecl)); } +/// Convert an AccessSpecifier into the corresponding DINode flag. +/// As an optimization, return 0 if the access specifier equals the +/// default for the containing type. +static llvm::DINode::DIFlags getAccessFlag(AccessSpecifier Access, + const RecordDecl *RD) { + AccessSpecifier Default = clang::AS_none; + if (RD && RD->isClass()) + Default = clang::AS_private; + else if (RD && (RD->isStruct() || RD->isUnion())) + Default = clang::AS_public; + + if (Access == Default) + return llvm::DINode::FlagZero; + + switch (Access) { + case clang::AS_private: + return llvm::DINode::FlagPrivate; + case clang::AS_protected: + return llvm::DINode::FlagProtected; + case clang::AS_public: + return llvm::DINode::FlagPublic; + case clang::AS_none: + return llvm::DINode::FlagZero; + } + llvm_unreachable("unexpected access enumerator"); +} + llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile *Unit) { llvm::DIType *Underlying = @@ -1249,9 +1391,17 @@ llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty, uint32_t Align = getDeclAlignIfRequired(Ty->getDecl(), CGM.getContext()); // Typedefs are derived from some other type. + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(Ty->getDecl()); + + llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; + const DeclContext *DC = Ty->getDecl()->getDeclContext(); + if (isa<RecordDecl>(DC)) + Flags = getAccessFlag(Ty->getDecl()->getAccess(), cast<RecordDecl>(DC)); + return DBuilder.createTypedef(Underlying, Ty->getDecl()->getName(), getOrCreateFile(Loc), getLineNumber(Loc), - getDeclContextDescriptor(Ty->getDecl()), Align); + getDeclContextDescriptor(Ty->getDecl()), Align, + Flags, Annotations); } static unsigned getDwarfCC(CallingConv CC) { @@ -1276,6 +1426,7 @@ static unsigned getDwarfCC(CallingConv CC) { return llvm::dwarf::DW_CC_LLVM_X86_64SysV; case CC_AAPCS: case CC_AArch64VectorCall: + case CC_AArch64SVEPCS: return llvm::dwarf::DW_CC_LLVM_AAPCS; case CC_AAPCS_VFP: return llvm::dwarf::DW_CC_LLVM_AAPCS_VFP; @@ -1284,6 +1435,7 @@ static unsigned getDwarfCC(CallingConv CC) { case CC_SpirFunction: return llvm::dwarf::DW_CC_LLVM_SpirFunction; case CC_OpenCLKernel: + case CC_AMDGPUKernelCall: return llvm::dwarf::DW_CC_LLVM_OpenCLKernel; case CC_Swift: return llvm::dwarf::DW_CC_LLVM_Swift; @@ -1296,22 +1448,43 @@ static unsigned getDwarfCC(CallingConv CC) { return llvm::dwarf::DW_CC_LLVM_PreserveAll; case CC_X86RegCall: return llvm::dwarf::DW_CC_LLVM_X86RegCall; + case CC_M68kRTD: + return llvm::dwarf::DW_CC_LLVM_M68kRTD; } return 0; } +static llvm::DINode::DIFlags getRefFlags(const FunctionProtoType *Func) { + llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; + if (Func->getExtProtoInfo().RefQualifier == RQ_LValue) + Flags |= llvm::DINode::FlagLValueReference; + if (Func->getExtProtoInfo().RefQualifier == RQ_RValue) + Flags |= llvm::DINode::FlagRValueReference; + return Flags; +} + llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty, llvm::DIFile *Unit) { + const auto *FPT = dyn_cast<FunctionProtoType>(Ty); + if (FPT) { + if (llvm::DIType *QTy = CreateQualifiedType(FPT, Unit)) + return QTy; + } + + // Create the type without any qualifiers + SmallVector<llvm::Metadata *, 16> EltTys; // Add the result type at least. EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit)); + llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; // Set up remainder of arguments if there is a prototype. // otherwise emit it as a variadic function. - if (isa<FunctionNoProtoType>(Ty)) + if (!FPT) { EltTys.push_back(DBuilder.createUnspecifiedParameter()); - else if (const auto *FPT = dyn_cast<FunctionProtoType>(Ty)) { + } else { + Flags = getRefFlags(FPT); for (const QualType &ParamType : FPT->param_types()) EltTys.push_back(getOrCreateType(ParamType, Unit)); if (FPT->isVariadic()) @@ -1319,42 +1492,18 @@ llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty, } llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys); - return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero, - getDwarfCC(Ty->getCallConv())); -} - -/// Convert an AccessSpecifier into the corresponding DINode flag. -/// As an optimization, return 0 if the access specifier equals the -/// default for the containing type. -static llvm::DINode::DIFlags getAccessFlag(AccessSpecifier Access, - const RecordDecl *RD) { - AccessSpecifier Default = clang::AS_none; - if (RD && RD->isClass()) - Default = clang::AS_private; - else if (RD && (RD->isStruct() || RD->isUnion())) - Default = clang::AS_public; - - if (Access == Default) - return llvm::DINode::FlagZero; - - switch (Access) { - case clang::AS_private: - return llvm::DINode::FlagPrivate; - case clang::AS_protected: - return llvm::DINode::FlagProtected; - case clang::AS_public: - return llvm::DINode::FlagPublic; - case clang::AS_none: - return llvm::DINode::FlagZero; - } - llvm_unreachable("unexpected access enumerator"); + llvm::DIType *F = DBuilder.createSubroutineType( + EltTypeArray, Flags, getDwarfCC(Ty->getCallConv())); + return F; } -llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl, - llvm::DIScope *RecordTy, - const RecordDecl *RD) { +llvm::DIDerivedType * +CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl, + llvm::DIScope *RecordTy, const RecordDecl *RD) { StringRef Name = BitFieldDecl->getName(); QualType Ty = BitFieldDecl->getType(); + if (BitFieldDecl->hasAttr<PreferredTypeAttr>()) + Ty = BitFieldDecl->getAttr<PreferredTypeAttr>()->getType(); SourceLocation Loc = BitFieldDecl->getLocation(); llvm::DIFile *VUnit = getOrCreateFile(Loc); llvm::DIType *DebugType = getOrCreateType(Ty, VUnit); @@ -1377,16 +1526,88 @@ llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl, Offset = BitFieldInfo.StorageSize - BitFieldInfo.Size - Offset; uint64_t OffsetInBits = StorageOffsetInBits + Offset; llvm::DINode::DIFlags Flags = getAccessFlag(BitFieldDecl->getAccess(), RD); + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(BitFieldDecl); return DBuilder.createBitFieldMemberType( RecordTy, Name, File, Line, SizeInBits, OffsetInBits, StorageOffsetInBits, - Flags, DebugType); + Flags, DebugType, Annotations); +} + +llvm::DIDerivedType *CGDebugInfo::createBitFieldSeparatorIfNeeded( + const FieldDecl *BitFieldDecl, const llvm::DIDerivedType *BitFieldDI, + llvm::ArrayRef<llvm::Metadata *> PreviousFieldsDI, const RecordDecl *RD) { + + if (!CGM.getTargetCodeGenInfo().shouldEmitDWARFBitFieldSeparators()) + return nullptr; + + /* + Add a *single* zero-bitfield separator between two non-zero bitfields + separated by one or more zero-bitfields. This is used to distinguish between + structures such the ones below, where the memory layout is the same, but how + the ABI assigns fields to registers differs. + + struct foo { + int space[4]; + char a : 8; // on amdgpu, passed on v4 + char b : 8; + char x : 8; + char y : 8; + }; + struct bar { + int space[4]; + char a : 8; // on amdgpu, passed on v4 + char b : 8; + char : 0; + char x : 8; // passed on v5 + char y : 8; + }; + */ + if (PreviousFieldsDI.empty()) + return nullptr; + + // If we already emitted metadata for a 0-length bitfield, nothing to do here. + auto *PreviousMDEntry = + PreviousFieldsDI.empty() ? nullptr : PreviousFieldsDI.back(); + auto *PreviousMDField = + dyn_cast_or_null<llvm::DIDerivedType>(PreviousMDEntry); + if (!PreviousMDField || !PreviousMDField->isBitField() || + PreviousMDField->getSizeInBits() == 0) + return nullptr; + + auto PreviousBitfield = RD->field_begin(); + std::advance(PreviousBitfield, BitFieldDecl->getFieldIndex() - 1); + + assert(PreviousBitfield->isBitField()); + + ASTContext &Context = CGM.getContext(); + if (!PreviousBitfield->isZeroLengthBitField(Context)) + return nullptr; + + QualType Ty = PreviousBitfield->getType(); + SourceLocation Loc = PreviousBitfield->getLocation(); + llvm::DIFile *VUnit = getOrCreateFile(Loc); + llvm::DIType *DebugType = getOrCreateType(Ty, VUnit); + llvm::DIScope *RecordTy = BitFieldDI->getScope(); + + llvm::DIFile *File = getOrCreateFile(Loc); + unsigned Line = getLineNumber(Loc); + + uint64_t StorageOffsetInBits = + cast<llvm::ConstantInt>(BitFieldDI->getStorageOffsetInBits()) + ->getZExtValue(); + + llvm::DINode::DIFlags Flags = + getAccessFlag(PreviousBitfield->getAccess(), RD); + llvm::DINodeArray Annotations = + CollectBTFDeclTagAnnotations(*PreviousBitfield); + return DBuilder.createBitFieldMemberType( + RecordTy, "", File, Line, 0, StorageOffsetInBits, StorageOffsetInBits, + Flags, DebugType, Annotations); } -llvm::DIType * -CGDebugInfo::createFieldType(StringRef name, QualType type, SourceLocation loc, - AccessSpecifier AS, uint64_t offsetInBits, - uint32_t AlignInBits, llvm::DIFile *tunit, - llvm::DIScope *scope, const RecordDecl *RD) { +llvm::DIType *CGDebugInfo::createFieldType( + StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS, + uint64_t offsetInBits, uint32_t AlignInBits, llvm::DIFile *tunit, + llvm::DIScope *scope, const RecordDecl *RD, llvm::DINodeArray Annotations) { llvm::DIType *debugType = getOrCreateType(type, tunit); // Get the location for the field. @@ -1404,7 +1625,7 @@ CGDebugInfo::createFieldType(StringRef name, QualType type, SourceLocation loc, llvm::DINode::DIFlags flags = getAccessFlag(AS, RD); return DBuilder.createMemberType(scope, name, file, line, SizeInBits, Align, - offsetInBits, flags, debugType); + offsetInBits, flags, debugType, Annotations); } void CGDebugInfo::CollectRecordLambdaFields( @@ -1423,7 +1644,7 @@ void CGDebugInfo::CollectRecordLambdaFields( if (C.capturesVariable()) { SourceLocation Loc = C.getLocation(); assert(!Field->isBitField() && "lambdas don't have bitfield members!"); - VarDecl *V = C.getCapturedVar(); + ValueDecl *V = C.getCapturedVar(); StringRef VName = V->getName(); llvm::DIFile *VUnit = getOrCreateFile(Loc); auto Align = getDeclAlignIfRequired(V, CGM.getContext()); @@ -1439,8 +1660,10 @@ void CGDebugInfo::CollectRecordLambdaFields( FieldDecl *f = *Field; llvm::DIFile *VUnit = getOrCreateFile(f->getLocation()); QualType type = f->getType(); + StringRef ThisName = + CGM.getCodeGenOpts().EmitCodeView ? "__this" : "this"; llvm::DIType *fieldType = createFieldType( - "this", type, f->getLocation(), f->getAccess(), + ThisName, type, f->getLocation(), f->getAccess(), layout.getFieldOffset(fieldno), VUnit, RecordTy, CXXDecl); elements.push_back(fieldType); @@ -1459,6 +1682,9 @@ CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy, unsigned LineNumber = getLineNumber(Var->getLocation()); StringRef VName = Var->getName(); + + // FIXME: to avoid complications with type merging we should + // emit the constant on the definition instead of the declaration. llvm::Constant *C = nullptr; if (Var->getInit()) { const APValue *Value = Var->evaluateValue(); @@ -1471,9 +1697,12 @@ CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy, } llvm::DINode::DIFlags Flags = getAccessFlag(Var->getAccess(), RD); + auto Tag = CGM.getCodeGenOpts().DwarfVersion >= 5 + ? llvm::dwarf::DW_TAG_variable + : llvm::dwarf::DW_TAG_member; auto Align = getDeclAlignIfRequired(Var, CGM.getContext()); llvm::DIDerivedType *GV = DBuilder.createStaticMemberType( - RecordTy, VName, VUnit, LineNumber, VTy, Flags, C, Align); + RecordTy, VName, VUnit, LineNumber, VTy, Flags, C, Tag, Align); StaticDataMemberCache[Var->getCanonicalDecl()].reset(GV); return GV; } @@ -1491,12 +1720,17 @@ void CGDebugInfo::CollectRecordNormalField( llvm::DIType *FieldType; if (field->isBitField()) { - FieldType = createBitFieldType(field, RecordTy, RD); + llvm::DIDerivedType *BitFieldType; + FieldType = BitFieldType = createBitFieldType(field, RecordTy, RD); + if (llvm::DIType *Separator = + createBitFieldSeparatorIfNeeded(field, BitFieldType, elements, RD)) + elements.push_back(Separator); } else { auto Align = getDeclAlignIfRequired(field, CGM.getContext()); + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(field); FieldType = createFieldType(name, type, field->getLocation(), field->getAccess(), - OffsetInBits, Align, tunit, RecordTy, RD); + OffsetInBits, Align, tunit, RecordTy, RD, Annotations); } elements.push_back(FieldType); @@ -1562,52 +1796,66 @@ void CGDebugInfo::CollectRecordFields( } else if (CGM.getCodeGenOpts().EmitCodeView) { // Debug info for nested types is included in the member list only for // CodeView. - if (const auto *nestedType = dyn_cast<TypeDecl>(I)) + if (const auto *nestedType = dyn_cast<TypeDecl>(I)) { + // MSVC doesn't generate nested type for anonymous struct/union. + if (isa<RecordDecl>(I) && + cast<RecordDecl>(I)->isAnonymousStructOrUnion()) + continue; if (!nestedType->isImplicit() && nestedType->getDeclContext() == record) CollectRecordNestedType(nestedType, elements); + } } } } llvm::DISubroutineType * CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, - llvm::DIFile *Unit, bool decl) { + llvm::DIFile *Unit) { const FunctionProtoType *Func = Method->getType()->getAs<FunctionProtoType>(); if (Method->isStatic()) return cast_or_null<llvm::DISubroutineType>( getOrCreateType(QualType(Func, 0), Unit)); - return getOrCreateInstanceMethodType(Method->getThisType(), Func, Unit, decl); -} + return getOrCreateInstanceMethodType(Method->getThisType(), Func, Unit); +} + +llvm::DISubroutineType *CGDebugInfo::getOrCreateInstanceMethodType( + QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile *Unit) { + FunctionProtoType::ExtProtoInfo EPI = Func->getExtProtoInfo(); + Qualifiers &Qc = EPI.TypeQuals; + Qc.removeConst(); + Qc.removeVolatile(); + Qc.removeRestrict(); + Qc.removeUnaligned(); + // Keep the removed qualifiers in sync with + // CreateQualifiedType(const FunctionPrototype*, DIFile *Unit) + // On a 'real' member function type, these qualifiers are carried on the type + // of the first parameter, not as separate DW_TAG_const_type (etc) decorator + // tags around them. (But, in the raw function types with qualifiers, they have + // to use wrapper types.) -llvm::DISubroutineType * -CGDebugInfo::getOrCreateInstanceMethodType(QualType ThisPtr, - const FunctionProtoType *Func, - llvm::DIFile *Unit, bool decl) { // Add "this" pointer. - llvm::DITypeRefArray Args( - cast<llvm::DISubroutineType>(getOrCreateType(QualType(Func, 0), Unit)) - ->getTypeArray()); + const auto *OriginalFunc = cast<llvm::DISubroutineType>( + getOrCreateType(CGM.getContext().getFunctionType( + Func->getReturnType(), Func->getParamTypes(), EPI), + Unit)); + llvm::DITypeRefArray Args = OriginalFunc->getTypeArray(); assert(Args.size() && "Invalid number of arguments!"); SmallVector<llvm::Metadata *, 16> Elts; + // First element is always return type. For 'void' functions it is NULL. - QualType temp = Func->getReturnType(); - if (temp->getTypeClass() == Type::Auto && decl) - Elts.push_back(CreateType(cast<AutoType>(temp))); - else - Elts.push_back(Args[0]); + Elts.push_back(Args[0]); // "this" pointer is always first argument. const CXXRecordDecl *RD = ThisPtr->getPointeeCXXRecordDecl(); if (isa<ClassTemplateSpecializationDecl>(RD)) { // Create pointer type directly in this case. const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr); - QualType PointeeTy = ThisPtrTy->getPointeeType(); - unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); - uint64_t Size = CGM.getTarget().getPointerWidth(AS); + uint64_t Size = CGM.getContext().getTypeSize(ThisPtrTy); auto Align = getTypeAlignIfRequired(ThisPtrTy, CGM.getContext()); - llvm::DIType *PointeeType = getOrCreateType(PointeeTy, Unit); + llvm::DIType *PointeeType = + getOrCreateType(ThisPtrTy->getPointeeType(), Unit); llvm::DIType *ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align); TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType); @@ -1629,13 +1877,7 @@ CGDebugInfo::getOrCreateInstanceMethodType(QualType ThisPtr, llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts); - llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; - if (Func->getExtProtoInfo().RefQualifier == RQ_LValue) - Flags |= llvm::DINode::FlagLValueReference; - if (Func->getExtProtoInfo().RefQualifier == RQ_RValue) - Flags |= llvm::DINode::FlagRValueReference; - - return DBuilder.createSubroutineType(EltTypeArray, Flags, + return DBuilder.createSubroutineType(EltTypeArray, OriginalFunc->getFlags(), getDwarfCC(Func->getCallConv())); } @@ -1655,7 +1897,7 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method); StringRef MethodName = getFunctionName(Method); - llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit, true); + llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit); // Since a single ctor/dtor corresponds to multiple functions, it doesn't // make sense to give a single ctor/dtor a linkage name. @@ -1683,8 +1925,8 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero; int ThisAdjustment = 0; - if (Method->isVirtual()) { - if (Method->isPure()) + if (VTableContextBase::hasVtableSlot(Method)) { + if (Method->isPureVirtual()) SPFlags |= llvm::DISubprogram::SPFlagPureVirtual; else SPFlags |= llvm::DISubprogram::SPFlagVirtual; @@ -1721,27 +1963,8 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( ContainingType = RecordTy; } - // We're checking for deleted C++ special member functions - // [Ctors,Dtors, Copy/Move] - auto checkAttrDeleted = [&](const auto *Method) { - if (Method->getCanonicalDecl()->isDeleted()) - SPFlags |= llvm::DISubprogram::SPFlagDeleted; - }; - - switch (Method->getKind()) { - - case Decl::CXXConstructor: - case Decl::CXXDestructor: - checkAttrDeleted(Method); - break; - case Decl::CXXMethod: - if (Method->isCopyAssignmentOperator() || - Method->isMoveAssignmentOperator()) - checkAttrDeleted(Method); - break; - default: - break; - } + if (Method->getCanonicalDecl()->isDeleted()) + SPFlags |= llvm::DISubprogram::SPFlagDeleted; if (Method->isNoReturn()) Flags |= llvm::DINode::FlagNoReturn; @@ -1771,7 +1994,7 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( // In this debug mode, emit type info for a class when its constructor type // info is emitted. - if (DebugKind == codegenoptions::DebugInfoConstructor) + if (DebugKind == llvm::codegenoptions::DebugInfoConstructor) if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method)) completeUnusedClass(*CD->getParent()); @@ -1887,43 +2110,28 @@ void CGDebugInfo::CollectCXXBasesAux( } llvm::DINodeArray -CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, - ArrayRef<TemplateArgument> TAList, +CGDebugInfo::CollectTemplateParams(std::optional<TemplateArgs> OArgs, llvm::DIFile *Unit) { + if (!OArgs) + return llvm::DINodeArray(); + TemplateArgs &Args = *OArgs; SmallVector<llvm::Metadata *, 16> TemplateParams; - for (unsigned i = 0, e = TAList.size(); i != e; ++i) { - const TemplateArgument &TA = TAList[i]; + for (unsigned i = 0, e = Args.Args.size(); i != e; ++i) { + const TemplateArgument &TA = Args.Args[i]; StringRef Name; - bool defaultParameter = false; - if (TPList) - Name = TPList->getParam(i)->getName(); + const bool defaultParameter = TA.getIsDefaulted(); + if (Args.TList) + Name = Args.TList->getParam(i)->getName(); + switch (TA.getKind()) { case TemplateArgument::Type: { llvm::DIType *TTy = getOrCreateType(TA.getAsType(), Unit); - - if (TPList) - if (auto *templateType = - dyn_cast_or_null<TemplateTypeParmDecl>(TPList->getParam(i))) - if (templateType->hasDefaultArgument()) - defaultParameter = - templateType->getDefaultArgument() == TA.getAsType(); - TemplateParams.push_back(DBuilder.createTemplateTypeParameter( TheCU, Name, TTy, defaultParameter)); } break; case TemplateArgument::Integral: { llvm::DIType *TTy = getOrCreateType(TA.getIntegralType(), Unit); - if (TPList && CGM.getCodeGenOpts().DwarfVersion >= 5) - if (auto *templateType = - dyn_cast_or_null<NonTypeTemplateParmDecl>(TPList->getParam(i))) - if (templateType->hasDefaultArgument() && - !templateType->getDefaultArgument()->isValueDependent()) - defaultParameter = llvm::APSInt::isSameValue( - templateType->getDefaultArgument()->EvaluateKnownConstInt( - CGM.getContext()), - TA.getAsIntegral()); - TemplateParams.push_back(DBuilder.createTemplateValueParameter( TheCU, Name, TTy, defaultParameter, llvm::ConstantInt::get(CGM.getLLVMContext(), TA.getAsIntegral()))); @@ -1937,14 +2145,14 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, // attribute, i.e. that value is not available at the host side. if (!CGM.getLangOpts().CUDA || CGM.getLangOpts().CUDAIsDevice || !D->hasAttr<CUDADeviceAttr>()) { - const CXXMethodDecl *MD; // Variable pointer template parameters have a value that is the address // of the variable. if (const auto *VD = dyn_cast<VarDecl>(D)) V = CGM.GetAddrOfGlobalVar(VD); // Member function pointers have special support for building them, // though this is currently unsupported in LLVM CodeGen. - else if ((MD = dyn_cast<CXXMethodDecl>(D)) && MD->isInstance()) + else if (const auto *MD = dyn_cast<CXXMethodDecl>(D); + MD && MD->isImplicitObjectMemberFunction()) V = CGM.getCXXABI().EmitMemberFunctionPointer(MD); else if (const auto *FD = dyn_cast<FunctionDecl>(D)) V = CGM.GetAddrOfFunction(FD); @@ -1993,15 +2201,27 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, TemplateParams.push_back(DBuilder.createTemplateValueParameter( TheCU, Name, TTy, defaultParameter, V)); } break; - case TemplateArgument::Template: + case TemplateArgument::StructuralValue: { + QualType T = TA.getStructuralValueType(); + llvm::DIType *TTy = getOrCreateType(T, Unit); + llvm::Constant *V = ConstantEmitter(CGM).emitAbstract( + SourceLocation(), TA.getAsStructuralValue(), T); + TemplateParams.push_back(DBuilder.createTemplateValueParameter( + TheCU, Name, TTy, defaultParameter, V)); + } break; + case TemplateArgument::Template: { + std::string QualName; + llvm::raw_string_ostream OS(QualName); + TA.getAsTemplate().getAsTemplateDecl()->printQualifiedName( + OS, getPrintingPolicy()); TemplateParams.push_back(DBuilder.createTemplateTemplateParameter( - TheCU, Name, nullptr, - TA.getAsTemplate().getAsTemplateDecl()->getQualifiedNameAsString())); + TheCU, Name, nullptr, OS.str(), defaultParameter)); break; + } case TemplateArgument::Pack: TemplateParams.push_back(DBuilder.createTemplateParameterPack( TheCU, Name, nullptr, - CollectTemplateParams(nullptr, TA.getPackAsArray(), Unit))); + CollectTemplateParams({{nullptr, TA.getPackAsArray()}}, Unit))); break; case TemplateArgument::Expression: { const Expr *E = TA.getAsExpr(); @@ -2024,43 +2244,72 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, return DBuilder.getOrCreateArray(TemplateParams); } -llvm::DINodeArray -CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD, - llvm::DIFile *Unit) { +std::optional<CGDebugInfo::TemplateArgs> +CGDebugInfo::GetTemplateArgs(const FunctionDecl *FD) const { if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplateSpecialization) { const TemplateParameterList *TList = FD->getTemplateSpecializationInfo() ->getTemplate() ->getTemplateParameters(); - return CollectTemplateParams( - TList, FD->getTemplateSpecializationArgs()->asArray(), Unit); + return {{TList, FD->getTemplateSpecializationArgs()->asArray()}}; } - return llvm::DINodeArray(); + return std::nullopt; } - -llvm::DINodeArray CGDebugInfo::CollectVarTemplateParams(const VarDecl *VL, - llvm::DIFile *Unit) { +std::optional<CGDebugInfo::TemplateArgs> +CGDebugInfo::GetTemplateArgs(const VarDecl *VD) const { // Always get the full list of parameters, not just the ones from the // specialization. A partial specialization may have fewer parameters than // there are arguments. - auto *TS = dyn_cast<VarTemplateSpecializationDecl>(VL); + auto *TS = dyn_cast<VarTemplateSpecializationDecl>(VD); if (!TS) - return llvm::DINodeArray(); + return std::nullopt; VarTemplateDecl *T = TS->getSpecializedTemplate(); const TemplateParameterList *TList = T->getTemplateParameters(); auto TA = TS->getTemplateArgs().asArray(); - return CollectTemplateParams(TList, TA, Unit); + return {{TList, TA}}; +} +std::optional<CGDebugInfo::TemplateArgs> +CGDebugInfo::GetTemplateArgs(const RecordDecl *RD) const { + if (auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { + // Always get the full list of parameters, not just the ones from the + // specialization. A partial specialization may have fewer parameters than + // there are arguments. + TemplateParameterList *TPList = + TSpecial->getSpecializedTemplate()->getTemplateParameters(); + const TemplateArgumentList &TAList = TSpecial->getTemplateArgs(); + return {{TPList, TAList.asArray()}}; + } + return std::nullopt; } -llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams( - const ClassTemplateSpecializationDecl *TSpecial, llvm::DIFile *Unit) { - // Always get the full list of parameters, not just the ones from the - // specialization. A partial specialization may have fewer parameters than - // there are arguments. - TemplateParameterList *TPList = - TSpecial->getSpecializedTemplate()->getTemplateParameters(); - const TemplateArgumentList &TAList = TSpecial->getTemplateArgs(); - return CollectTemplateParams(TPList, TAList.asArray(), Unit); +llvm::DINodeArray +CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD, + llvm::DIFile *Unit) { + return CollectTemplateParams(GetTemplateArgs(FD), Unit); +} + +llvm::DINodeArray CGDebugInfo::CollectVarTemplateParams(const VarDecl *VL, + llvm::DIFile *Unit) { + return CollectTemplateParams(GetTemplateArgs(VL), Unit); +} + +llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams(const RecordDecl *RD, + llvm::DIFile *Unit) { + return CollectTemplateParams(GetTemplateArgs(RD), Unit); +} + +llvm::DINodeArray CGDebugInfo::CollectBTFDeclTagAnnotations(const Decl *D) { + if (!D->hasAttr<BTFDeclTagAttr>()) + return nullptr; + + SmallVector<llvm::Metadata *, 4> Annotations; + for (const auto *I : D->specific_attrs<BTFDeclTagAttr>()) { + llvm::Metadata *Ops[2] = { + llvm::MDString::get(CGM.getLLVMContext(), StringRef("btf_decl_tag")), + llvm::MDString::get(CGM.getLLVMContext(), I->getBTFDeclTag())}; + Annotations.push_back(llvm::MDNode::get(CGM.getLLVMContext(), Ops)); + } + return DBuilder.getOrCreateArray(Annotations); } llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) { @@ -2075,7 +2324,7 @@ llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) { llvm::DIType *SubTy = DBuilder.createSubroutineType(SElements); unsigned Size = Context.getTypeSize(Context.VoidPtrTy); unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace(); - Optional<unsigned> DWARFAddressSpace = + std::optional<unsigned> DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace); llvm::DIType *vtbl_ptr_type = DBuilder.createPointerType( @@ -2172,7 +2421,7 @@ void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit, VFTLayout.vtable_components().size() - CGM.getLangOpts().RTTIData; unsigned VTableWidth = PtrWidth * VSlotCount; unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace(); - Optional<unsigned> DWARFAddressSpace = + std::optional<unsigned> DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace); // Create a very wide void* type and insert it directly in the element list. @@ -2225,11 +2474,11 @@ void CGDebugInfo::addHeapAllocSiteMetadata(llvm::CallBase *CI, QualType AllocatedTy, SourceLocation Loc) { if (CGM.getCodeGenOpts().getDebugInfo() <= - codegenoptions::DebugLineTablesOnly) + llvm::codegenoptions::DebugLineTablesOnly) return; llvm::MDNode *node; if (AllocatedTy->isVoidType()) - node = llvm::MDNode::get(CGM.getLLVMContext(), None); + node = llvm::MDNode::get(CGM.getLLVMContext(), std::nullopt); else node = getOrCreateType(AllocatedTy, getOrCreateFile(Loc)); @@ -2237,7 +2486,7 @@ void CGDebugInfo::addHeapAllocSiteMetadata(llvm::CallBase *CI, } void CGDebugInfo::completeType(const EnumDecl *ED) { - if (DebugKind <= codegenoptions::DebugLineTablesOnly) + if (DebugKind <= llvm::codegenoptions::DebugLineTablesOnly) return; QualType Ty = CGM.getContext().getEnumType(ED); void *TyPtr = Ty.getAsOpaquePtr(); @@ -2250,7 +2499,7 @@ void CGDebugInfo::completeType(const EnumDecl *ED) { } void CGDebugInfo::completeType(const RecordDecl *RD) { - if (DebugKind > codegenoptions::LimitedDebugInfo || + if (DebugKind > llvm::codegenoptions::LimitedDebugInfo || !CGM.getLangOpts().CPlusPlus) completeRequiredType(RD); } @@ -2312,14 +2561,18 @@ void CGDebugInfo::completeClassData(const RecordDecl *RD) { } void CGDebugInfo::completeClass(const RecordDecl *RD) { - if (DebugKind <= codegenoptions::DebugLineTablesOnly) + if (DebugKind <= llvm::codegenoptions::DebugLineTablesOnly) return; QualType Ty = CGM.getContext().getRecordType(RD); void *TyPtr = Ty.getAsOpaquePtr(); auto I = TypeCache.find(TyPtr); if (I != TypeCache.end() && !cast<llvm::DIType>(I->second)->isForwardDecl()) return; - llvm::DIType *Res = CreateTypeDefinition(Ty->castAs<RecordType>()); + + // We want the canonical definition of the structure to not + // be the typedef. Since that would lead to circular typedef + // metadata. + auto [Res, PrefRes] = CreateTypeDefinition(Ty->castAs<RecordType>()); assert(!Res->isForwardDecl()); TypeCache[TyPtr].reset(Res); } @@ -2346,12 +2599,21 @@ static bool canUseCtorHoming(const CXXRecordDecl *RD) { if (isClassOrMethodDLLImport(RD)) return false; - return !RD->isLambda() && !RD->isAggregate() && - !RD->hasTrivialDefaultConstructor() && - !RD->hasConstexprNonCopyMoveConstructor(); + if (RD->isLambda() || RD->isAggregate() || + RD->hasTrivialDefaultConstructor() || + RD->hasConstexprNonCopyMoveConstructor()) + return false; + + for (const CXXConstructorDecl *Ctor : RD->ctors()) { + if (Ctor->isCopyOrMoveConstructor()) + continue; + if (!Ctor->isDeleted()) + return true; + } + return false; } -static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind, +static bool shouldOmitDefinition(llvm::codegenoptions::DebugInfoKind DebugKind, bool DebugTypeExtRefs, const RecordDecl *RD, const LangOptions &LangOpts) { if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition())) @@ -2364,10 +2626,10 @@ static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind, // Only emit forward declarations in line tables only to keep debug info size // small. This only applies to CodeView, since we don't emit types in DWARF // line tables only. - if (DebugKind == codegenoptions::DebugLineTablesOnly) + if (DebugKind == llvm::codegenoptions::DebugLineTablesOnly) return true; - if (DebugKind > codegenoptions::LimitedDebugInfo || + if (DebugKind > llvm::codegenoptions::LimitedDebugInfo || RD->hasAttr<StandaloneDebugAttr>()) return false; @@ -2403,7 +2665,7 @@ static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind, // In constructor homing mode, only emit complete debug info for a class // when its constructor is emitted. - if ((DebugKind == codegenoptions::DebugInfoConstructor) && + if ((DebugKind == llvm::codegenoptions::DebugInfoConstructor) && canUseCtorHoming(CXXDecl)) return true; @@ -2430,10 +2692,25 @@ llvm::DIType *CGDebugInfo::CreateType(const RecordType *Ty) { return T; } - return CreateTypeDefinition(Ty); + auto [Def, Pref] = CreateTypeDefinition(Ty); + + return Pref ? Pref : Def; } -llvm::DIType *CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) { +llvm::DIType *CGDebugInfo::GetPreferredNameType(const CXXRecordDecl *RD, + llvm::DIFile *Unit) { + if (!RD) + return nullptr; + + auto const *PNA = RD->getAttr<PreferredNameAttr>(); + if (!PNA) + return nullptr; + + return getOrCreateType(PNA->getTypedefType(), Unit); +} + +std::pair<llvm::DIType *, llvm::DIType *> +CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) { RecordDecl *RD = Ty->getDecl(); // Get overall information about the record type for the debug info. @@ -2449,7 +2726,7 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) { const RecordDecl *D = RD->getDefinition(); if (!D || !D->isCompleteDefinition()) - return FwdDecl; + return {FwdDecl, nullptr}; if (const auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD)) CollectContainingType(CXXDecl, FwdDecl); @@ -2488,7 +2765,12 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) { llvm::MDNode::replaceWithPermanent(llvm::TempDICompositeType(FwdDecl)); RegionMap[Ty->getDecl()].reset(FwdDecl); - return FwdDecl; + + if (CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB) + if (auto *PrefDI = GetPreferredNameType(CXXDecl, DefUnit)) + return {FwdDecl, PrefDI}; + + return {FwdDecl, nullptr}; } llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectType *Ty, @@ -2612,7 +2894,7 @@ llvm::DIModule *CGDebugInfo::getOrCreateModuleRef(ASTSourceDescriptor Mod, // clang::Module object, but it won't actually be built or imported; it will // be textual. if (CreateSkeletonCU && IsRootModule && Mod.getASTFile().empty() && M) - assert(StringRef(M->Name).startswith(CGM.getLangOpts().ModuleName) && + assert(StringRef(M->Name).starts_with(CGM.getLangOpts().ModuleName) && "clang module without ASTFile must be specified by -fmodule-name"); // Return a StringRef to the remapped Path. @@ -2639,8 +2921,12 @@ llvm::DIModule *CGDebugInfo::getOrCreateModuleRef(ASTSourceDescriptor Mod, llvm::DIBuilder DIB(CGM.getModule()); SmallString<0> PCM; - if (!llvm::sys::path::is_absolute(Mod.getASTFile())) - PCM = Mod.getPath(); + if (!llvm::sys::path::is_absolute(Mod.getASTFile())) { + if (CGM.getHeaderSearchOpts().ModuleFileHomeIsCwd) + PCM = getCurrentDirname(); + else + PCM = Mod.getPath(); + } llvm::sys::path::append(PCM, Mod.getASTFile()); DIB.createCompileUnit( TheCU->getSourceLanguage(), @@ -2801,6 +3087,9 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, else if (Field->getAccessControl() == ObjCIvarDecl::Public) Flags = llvm::DINode::FlagPublic; + if (Field->isBitField()) + Flags |= llvm::DINode::FlagBitField; + llvm::MDNode *PropertyNode = nullptr; if (ObjCImplementationDecl *ImpD = ID->getImplementation()) { if (ObjCPropertyImplDecl *PImpD = @@ -2839,6 +3128,23 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, llvm::DIType *CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile *Unit) { + if (Ty->isExtVectorBoolType()) { + // Boolean ext_vector_type(N) are special because their real element type + // (bits of bit size) is not their Clang element type (_Bool of size byte). + // For now, we pretend the boolean vector were actually a vector of bytes + // (where each byte represents 8 bits of the actual vector). + // FIXME Debug info should actually represent this proper as a vector mask + // type. + auto &Ctx = CGM.getContext(); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t NumVectorBytes = Size / Ctx.getCharWidth(); + + // Construct the vector of 'char' type. + QualType CharVecTy = + Ctx.getVectorType(Ctx.CharTy, NumVectorBytes, VectorKind::Generic); + return CreateType(CharVecTy->getAs<VectorType>(), Unit); + } + llvm::DIType *ElementTy = getOrCreateType(Ty->getElementType(), Unit); int64_t Count = Ty->getNumElements(); @@ -3012,11 +3318,11 @@ llvm::DIType *CGDebugInfo::CreateType(const MemberPointerType *Ty, Flags); const FunctionProtoType *FPT = - Ty->getPointeeType()->getAs<FunctionProtoType>(); + Ty->getPointeeType()->castAs<FunctionProtoType>(); return DBuilder.createMemberPointerType( getOrCreateInstanceMethodType( CXXMethodDecl::getThisType(FPT, Ty->getMostRecentCXXRecordDecl()), - FPT, U, false), + FPT, U), ClassType, Size, /*Align=*/0, Flags); } @@ -3098,9 +3404,9 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const EnumType *Ty) { unsigned Line = getLineNumber(ED->getLocation()); llvm::DIScope *EnumContext = getDeclContextDescriptor(ED); llvm::DIType *ClassTy = getOrCreateType(ED->getIntegerType(), DefUnit); - return DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, - Line, Size, Align, EltArray, ClassTy, - Identifier, ED->isScoped()); + return DBuilder.createEnumerationType( + EnumContext, ED->getName(), DefUnit, Line, Size, Align, EltArray, ClassTy, + /*RunTimeLang=*/0, Identifier, ED->isScoped()); } llvm::DIMacro *CGDebugInfo::CreateMacro(llvm::DIMacroFile *Parent, @@ -3141,7 +3447,7 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType(); break; case Type::TypeOf: - T = cast<TypeOfType>(T)->getUnderlyingType(); + T = cast<TypeOfType>(T)->getUnmodifiedType(); break; case Type::Decltype: T = cast<DecltypeType>(T)->getUnderlyingType(); @@ -3152,9 +3458,15 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { case Type::Attributed: T = cast<AttributedType>(T)->getEquivalentType(); break; + case Type::BTFTagAttributed: + T = cast<BTFTagAttributedType>(T)->getWrappedType(); + break; case Type::Elaborated: T = cast<ElaboratedType>(T)->getNamedType(); break; + case Type::Using: + T = cast<UsingType>(T)->getUnderlyingType(); + break; case Type::Paren: T = cast<ParenType>(T)->getInnerType(); break; @@ -3201,7 +3513,8 @@ void CGDebugInfo::completeTemplateDefinition( } void CGDebugInfo::completeUnusedClass(const CXXRecordDecl &D) { - if (DebugKind <= codegenoptions::DebugLineTablesOnly) + if (DebugKind <= llvm::codegenoptions::DebugLineTablesOnly || + D.isDynamicClass()) return; completeClassData(&D); @@ -3331,8 +3644,8 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { case Type::Atomic: return CreateType(cast<AtomicType>(Ty), Unit); - case Type::ExtInt: - return CreateType(cast<ExtIntType>(Ty)); + case Type::BitInt: + return CreateType(cast<BitIntType>(Ty)); case Type::Pipe: return CreateType(cast<PipeType>(Ty), Unit); @@ -3341,10 +3654,12 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { case Type::Auto: case Type::Attributed: + case Type::BTFTagAttributed: case Type::Adjusted: case Type::Decayed: case Type::DeducedTemplateSpecialization: case Type::Elaborated: + case Type::Using: case Type::Paren: case Type::MacroQualified: case Type::SubstTemplateTypeParm: @@ -3413,7 +3728,11 @@ llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) { return getOrCreateRecordFwdDecl(Ty, RDContext); uint64_t Size = CGM.getContext().getTypeSize(Ty); - auto Align = getDeclAlignIfRequired(D, CGM.getContext()); + // __attribute__((aligned)) can increase or decrease alignment *except* on a + // struct or struct member, where it only increases alignment unless 'packed' + // is also specified. To handle this case, the `getTypeAlignIfRequired` needs + // to be used. + auto Align = getTypeAlignIfRequired(Ty, CGM.getContext()); SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU); @@ -3433,11 +3752,15 @@ llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) { // Record exports it symbols to the containing structure. if (CXXRD->isAnonymousStructOrUnion()) Flags |= llvm::DINode::FlagExportSymbols; + + Flags |= getAccessFlag(CXXRD->getAccess(), + dyn_cast<CXXRecordDecl>(CXXRD->getDeclContext())); } + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D); llvm::DICompositeType *RealDecl = DBuilder.createReplaceableCompositeType( getTagForRecord(RD), RDName, RDContext, DefUnit, Line, 0, Size, Align, - Flags, Identifier); + Flags, Identifier, Annotations); // Elements of composite types usually have back to the type, creating // uniquing cycles. Distinct nodes are more efficient. @@ -3453,7 +3776,7 @@ llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) { // them distinct if they are ODR-uniqued. if (Identifier.empty()) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; case llvm::dwarf::DW_TAG_structure_type: case llvm::dwarf::DW_TAG_union_type: @@ -3476,11 +3799,11 @@ llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) { void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD, llvm::DICompositeType *RealDecl) { // A class's primary base or the class itself contains the vtable. - llvm::DICompositeType *ContainingType = nullptr; + llvm::DIType *ContainingType = nullptr; const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) { // Seek non-virtual primary base root. - while (1) { + while (true) { const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase); const CXXRecordDecl *PBT = BRL.getPrimaryBase(); if (PBT && !BRL.isPrimaryBaseVirtual()) @@ -3488,9 +3811,8 @@ void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD, else break; } - ContainingType = cast<llvm::DICompositeType>( - getOrCreateType(QualType(PBase->getTypeForDecl(), 0), - getOrCreateFile(RD->getLocation()))); + ContainingType = getOrCreateType(QualType(PBase->getTypeForDecl(), 0), + getOrCreateFile(RD->getLocation())); } else if (RD->isDynamicClass()) ContainingType = RealDecl; @@ -3525,17 +3847,18 @@ void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit, // No need to replicate the linkage name if it isn't different from the // subprogram name, no need to have it at all unless coverage is enabled or // debug is set to more than just line tables or extra debug info is needed. - if (LinkageName == Name || (!CGM.getCodeGenOpts().EmitGcovArcs && - !CGM.getCodeGenOpts().EmitGcovNotes && - !CGM.getCodeGenOpts().DebugInfoForProfiling && - !CGM.getCodeGenOpts().PseudoProbeForProfiling && - DebugKind <= codegenoptions::DebugLineTablesOnly)) + if (LinkageName == Name || + (CGM.getCodeGenOpts().CoverageNotesFile.empty() && + CGM.getCodeGenOpts().CoverageDataFile.empty() && + !CGM.getCodeGenOpts().DebugInfoForProfiling && + !CGM.getCodeGenOpts().PseudoProbeForProfiling && + DebugKind <= llvm::codegenoptions::DebugLineTablesOnly)) LinkageName = StringRef(); // Emit the function scope in line tables only mode (if CodeView) to // differentiate between function names. if (CGM.getCodeGenOpts().hasReducedDebugInfo() || - (DebugKind == codegenoptions::DebugLineTablesOnly && + (DebugKind == llvm::codegenoptions::DebugLineTablesOnly && CGM.getCodeGenOpts().EmitCodeView)) { if (const NamespaceDecl *NSDecl = dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext())) @@ -3572,7 +3895,7 @@ void CGDebugInfo::collectVarDeclProps(const VarDecl *VD, llvm::DIFile *&Unit, QualType ET = CGM.getContext().getAsArrayType(T)->getElementType(); T = CGM.getContext().getConstantArrayType(ET, ConstVal, nullptr, - ArrayType::Normal, 0); + ArraySizeModifier::Normal, 0); } Name = VD->getName(); @@ -3702,6 +4025,17 @@ llvm::DINode *CGDebugInfo::getDeclarationOrDefinition(const Decl *D) { auto N = I->second; if (auto *GVE = dyn_cast_or_null<llvm::DIGlobalVariableExpression>(N)) return GVE->getVariable(); + return cast<llvm::DINode>(N); + } + + // Search imported declaration cache if it is already defined + // as imported declaration. + auto IE = ImportedDeclCache.find(D->getCanonicalDecl()); + + if (IE != ImportedDeclCache.end()) { + auto N = IE->second; + if (auto *GVE = dyn_cast_or_null<llvm::DIImportedEntity>(N)) + return cast<llvm::DINode>(GVE); return dyn_cast_or_null<llvm::DINode>(N); } @@ -3716,7 +4050,7 @@ llvm::DINode *CGDebugInfo::getDeclarationOrDefinition(const Decl *D) { } llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) { - if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly) + if (!D || DebugKind <= llvm::codegenoptions::DebugLineTablesOnly) return nullptr; const auto *FD = dyn_cast<FunctionDecl>(D); @@ -3739,7 +4073,7 @@ llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) { return SP; } - for (auto NextFD : FD->redecls()) { + for (auto *NextFD : FD->redecls()) { auto MI = SPCache.find(NextFD->getCanonicalDecl()); if (MI != SPCache.end()) { auto *SP = dyn_cast_or_null<llvm::DISubprogram>(MI->second); @@ -3753,7 +4087,7 @@ llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) { llvm::DISubprogram *CGDebugInfo::getObjCMethodDeclaration( const Decl *D, llvm::DISubroutineType *FnType, unsigned LineNo, llvm::DINode::DIFlags Flags, llvm::DISubprogram::DISPFlags SPFlags) { - if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly) + if (!D || DebugKind <= llvm::codegenoptions::DebugLineTablesOnly) return nullptr; const auto *OMD = dyn_cast<ObjCMethodDecl>(D); @@ -3793,14 +4127,15 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D, llvm::DIFile *F) { // In CodeView, we emit the function types in line tables only because the // only way to distinguish between functions is by display name and type. - if (!D || (DebugKind <= codegenoptions::DebugLineTablesOnly && + if (!D || (DebugKind <= llvm::codegenoptions::DebugLineTablesOnly && !CGM.getCodeGenOpts().EmitCodeView)) // Create fake but valid subroutine type. Otherwise -verify would fail, and // subprogram DIE will miss DW_AT_decl_file and DW_AT_decl_line fields. - return DBuilder.createSubroutineType(DBuilder.getOrCreateTypeArray(None)); + return DBuilder.createSubroutineType( + DBuilder.getOrCreateTypeArray(std::nullopt)); if (const auto *Method = dyn_cast<CXXMethodDecl>(D)) - return getOrCreateMethodType(Method, F, false); + return getOrCreateMethodType(Method, F); const auto *FTy = FnType->getAs<FunctionType>(); CallingConv CC = FTy ? FTy->getCallConv() : CallingConv::CC_C; @@ -3861,6 +4196,20 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D, return cast<llvm::DISubroutineType>(getOrCreateType(FnType, F)); } +QualType +CGDebugInfo::getFunctionType(const FunctionDecl *FD, QualType RetTy, + const SmallVectorImpl<const VarDecl *> &Args) { + CallingConv CC = CallingConv::CC_C; + if (FD) + if (const auto *SrcFnTy = FD->getType()->getAs<FunctionType>()) + CC = SrcFnTy->getCallConv(); + SmallVector<QualType, 16> ArgTypes; + for (const VarDecl *VD : Args) + ArgTypes.push_back(VD->getType()); + return CGM.getContext().getFunctionType(RetTy, ArgTypes, + FunctionProtoType::ExtProtoInfo(CC)); +} + void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc, SourceLocation ScopeLoc, QualType FnType, llvm::Function *Fn, bool CurFuncIsThunk) { @@ -3909,11 +4258,15 @@ void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc, Flags |= llvm::DINode::FlagPrototyped; } - if (Name.startswith("\01")) + if (Name.starts_with("\01")) Name = Name.substr(1); + assert((!D || !isa<VarDecl>(D) || + GD.getDynamicInitKind() != DynamicInitKind::NoStub) && + "Unexpected DynamicInitKind !"); + if (!HasDecl || D->isImplicit() || D->hasAttr<ArtificialAttr>() || - (isa<VarDecl>(D) && GD.getDynamicInitKind() != DynamicInitKind::NoStub)) { + isa<VarDecl>(D) || isa<CapturedDecl>(D)) { Flags |= llvm::DINode::FlagArtificial; // Artificial functions should not silently reuse CurLoc. CurLoc = SourceLocation(); @@ -3935,10 +4288,13 @@ void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc, unsigned ScopeLine = getLineNumber(ScopeLoc); llvm::DISubroutineType *DIFnType = getOrCreateFunctionType(D, FnType, Unit); llvm::DISubprogram *Decl = nullptr; - if (D) + llvm::DINodeArray Annotations = nullptr; + if (D) { Decl = isa<ObjCMethodDecl>(D) ? getObjCMethodDeclaration(D, DIFnType, LineNo, Flags, SPFlags) : getFunctionDeclaration(D); + Annotations = CollectBTFDeclTagAnnotations(D); + } // FIXME: The function declaration we're constructing here is mostly reusing // declarations from CXXMethodDecl and not constructing new ones for arbitrary @@ -3947,7 +4303,8 @@ void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc, // are emitted as CU level entities by the backend. llvm::DISubprogram *SP = DBuilder.createFunction( FDContext, Name, LinkageName, Unit, LineNo, DIFnType, ScopeLine, - FlagsForDef, SPFlagsForDef, TParamsArray.get(), Decl); + FlagsForDef, SPFlagsForDef, TParamsArray.get(), Decl, nullptr, + Annotations); Fn->setSubprogram(SP); // We might get here with a VarDecl in the case we're generating // code for the initialization of globals. Do not record these decls @@ -4006,10 +4363,28 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, if (CGM.getLangOpts().Optimize) SPFlags |= llvm::DISubprogram::SPFlagOptimized; + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D); + llvm::DISubroutineType *STy = getOrCreateFunctionType(D, FnType, Unit); llvm::DISubprogram *SP = DBuilder.createFunction( - FDContext, Name, LinkageName, Unit, LineNo, - getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags, - TParamsArray.get(), getFunctionDeclaration(D)); + FDContext, Name, LinkageName, Unit, LineNo, STy, ScopeLine, Flags, + SPFlags, TParamsArray.get(), nullptr, nullptr, Annotations); + + // Preserve btf_decl_tag attributes for parameters of extern functions + // for BPF target. The parameters created in this loop are attached as + // DISubprogram's retainedNodes in the subsequent finalizeSubprogram call. + if (IsDeclForCallSite && CGM.getTarget().getTriple().isBPF()) { + if (auto *FD = dyn_cast<FunctionDecl>(D)) { + llvm::DITypeRefArray ParamTypes = STy->getTypeArray(); + unsigned ArgNo = 1; + for (ParmVarDecl *PD : FD->parameters()) { + llvm::DINodeArray ParamAnnotations = CollectBTFDeclTagAnnotations(PD); + DBuilder.createParameterVariable( + SP, PD->getName(), ArgNo, Unit, LineNo, ParamTypes[ArgNo], true, + llvm::DINode::FlagZero, ParamAnnotations); + ++ArgNo; + } + } + } if (IsDeclForCallSite) Fn->setSubprogram(SP); @@ -4028,17 +4403,11 @@ void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke, if (Func->getSubprogram()) return; - // Do not emit a declaration subprogram for a builtin, a function with nodebug - // attribute, or if call site info isn't required. Also, elide declarations - // for functions with reserved names, as call site-related features aren't - // interesting in this case (& also, the compiler may emit calls to these - // functions without debug locations, which makes the verifier complain). - if (CalleeDecl->getBuiltinID() != 0 || CalleeDecl->hasAttr<NoDebugAttr>() || + // Do not emit a declaration subprogram for a function with nodebug + // attribute, or if call site info isn't required. + if (CalleeDecl->hasAttr<NoDebugAttr>() || getCallSiteRelatedAttrs() == llvm::DINode::FlagZero) return; - if (CalleeDecl->isReserved(CGM.getLangOpts()) != - ReservedIdentifierStatus::NotReserved) - return; // If there is no DISubprogram attached to the function being called, // create the one describing the function in order to have complete @@ -4091,14 +4460,14 @@ void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) { } void CGDebugInfo::AppendAddressSpaceXDeref( - unsigned AddressSpace, SmallVectorImpl<int64_t> &Expr) const { - Optional<unsigned> DWARFAddressSpace = + unsigned AddressSpace, SmallVectorImpl<uint64_t> &Expr) const { + std::optional<unsigned> DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(AddressSpace); if (!DWARFAddressSpace) return; Expr.push_back(llvm::dwarf::DW_OP_constu); - Expr.push_back(DWARFAddressSpace.getValue()); + Expr.push_back(*DWARFAddressSpace); Expr.push_back(llvm::dwarf::DW_OP_swap); Expr.push_back(llvm::dwarf::DW_OP_xderef); } @@ -4113,7 +4482,7 @@ void CGDebugInfo::EmitLexicalBlockStart(CGBuilderTy &Builder, CGM.getLLVMContext(), getLineNumber(Loc), getColumnNumber(Loc), LexicalBlockStack.back(), CurInlinedAt)); - if (DebugKind <= codegenoptions::DebugLineTablesOnly) + if (DebugKind <= llvm::codegenoptions::DebugLineTablesOnly) return; // Create a new lexical block and push it on the stack. @@ -4127,7 +4496,7 @@ void CGDebugInfo::EmitLexicalBlockEnd(CGBuilderTy &Builder, // Provide an entry in the line table for the end of the block. EmitLocation(Builder, Loc); - if (DebugKind <= codegenoptions::DebugLineTablesOnly) + if (DebugKind <= llvm::codegenoptions::DebugLineTablesOnly) return; LexicalBlockStack.pop_back(); @@ -4189,7 +4558,7 @@ CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, CharUnits Align = CGM.getContext().getDeclAlign(VD); if (Align > CGM.getContext().toCharUnitsFromBits( - CGM.getTarget().getPointerAlign(0))) { + CGM.getTarget().getPointerAlign(LangAS::Default))) { CharUnits FieldOffsetInBytes = CGM.getContext().toCharUnitsFromBits(FieldOffset); CharUnits AlignedOffsetInBytes = FieldOffsetInBytes.alignTo(Align); @@ -4198,7 +4567,7 @@ CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, if (NumPaddingBytes.isPositive()) { llvm::APInt pad(32, NumPaddingBytes.getQuantity()); FType = CGM.getContext().getConstantArrayType( - CGM.getContext().CharTy, pad, nullptr, ArrayType::Normal, 0); + CGM.getContext().CharTy, pad, nullptr, ArraySizeModifier::Normal, 0); EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset)); } } @@ -4223,7 +4592,7 @@ CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Value *Storage, - llvm::Optional<unsigned> ArgNo, + std::optional<unsigned> ArgNo, CGBuilderTy &Builder, const bool UsePointerValue) { assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); @@ -4256,21 +4625,21 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, Line = getLineNumber(VD->getLocation()); Column = getColumnNumber(VD->getLocation()); } - SmallVector<int64_t, 13> Expr; + SmallVector<uint64_t, 13> Expr; llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (VD->isImplicit()) Flags |= llvm::DINode::FlagArtificial; auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); - unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(VD->getType()); + unsigned AddressSpace = CGM.getTypes().getTargetAddressSpace(VD->getType()); AppendAddressSpaceXDeref(AddressSpace, Expr); // If this is implicit parameter of CXXThis or ObjCSelf kind, then give it an // object pointer flag. if (const auto *IPD = dyn_cast<ImplicitParamDecl>(VD)) { - if (IPD->getParameterKind() == ImplicitParamDecl::CXXThis || - IPD->getParameterKind() == ImplicitParamDecl::ObjCSelf) + if (IPD->getParameterKind() == ImplicitParamKind::CXXThis || + IPD->getParameterKind() == ImplicitParamKind::ObjCSelf) Flags |= llvm::DINode::FlagObjectPointer; } @@ -4289,7 +4658,7 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, Expr.push_back(llvm::dwarf::DW_OP_plus_uconst); // offset of __forwarding field offset = CGM.getContext().toCharUnitsFromBits( - CGM.getTarget().getPointerWidth(0)); + CGM.getTarget().getPointerWidth(LangAS::Default)); Expr.push_back(offset.getQuantity()); Expr.push_back(llvm::dwarf::DW_OP_deref); Expr.push_back(llvm::dwarf::DW_OP_plus_uconst); @@ -4337,8 +4706,7 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, // Use DW_OP_deref to tell the debugger to load the pointer and treat it as // the address of the variable. if (UsePointerValue) { - assert(std::find(Expr.begin(), Expr.end(), llvm::dwarf::DW_OP_deref) == - Expr.end() && + assert(!llvm::is_contained(Expr, llvm::dwarf::DW_OP_deref) && "Debug info already contains DW_OP_deref."); Expr.push_back(llvm::dwarf::DW_OP_deref); } @@ -4346,8 +4714,10 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, // Create the descriptor for the variable. llvm::DILocalVariable *D = nullptr; if (ArgNo) { + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(VD); D = DBuilder.createParameterVariable(Scope, Name, *ArgNo, Unit, Line, Ty, - CGM.getLangOpts().Optimize, Flags); + CGM.getLangOpts().Optimize, Flags, + Annotations); } else { // For normal local variable, we will try to find out whether 'VD' is the // copy parameter of coroutine. @@ -4400,12 +4770,147 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, return D; } +llvm::DIType *CGDebugInfo::CreateBindingDeclType(const BindingDecl *BD) { + llvm::DIFile *Unit = getOrCreateFile(BD->getLocation()); + + // If the declaration is bound to a bitfield struct field, its type may have a + // size that is different from its deduced declaration type's. + if (const MemberExpr *ME = dyn_cast<MemberExpr>(BD->getBinding())) { + if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) { + if (FD->isBitField()) { + ASTContext &Context = CGM.getContext(); + const CGRecordLayout &RL = + CGM.getTypes().getCGRecordLayout(FD->getParent()); + const CGBitFieldInfo &Info = RL.getBitFieldInfo(FD); + + // Find an integer type with the same bitwidth as the bitfield size. If + // no suitable type is present in the target, give up on producing debug + // information as it would be wrong. It is certainly possible to produce + // correct debug info, but the logic isn't currently implemented. + uint64_t BitfieldSizeInBits = Info.Size; + QualType IntTy = + Context.getIntTypeForBitwidth(BitfieldSizeInBits, Info.IsSigned); + if (IntTy.isNull()) + return nullptr; + Qualifiers Quals = BD->getType().getQualifiers(); + QualType FinalTy = Context.getQualifiedType(IntTy, Quals); + llvm::DIType *Ty = getOrCreateType(FinalTy, Unit); + assert(Ty); + return Ty; + } + } + } + + return getOrCreateType(BD->getType(), Unit); +} + +llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const BindingDecl *BD, + llvm::Value *Storage, + std::optional<unsigned> ArgNo, + CGBuilderTy &Builder, + const bool UsePointerValue) { + assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); + assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); + if (BD->hasAttr<NoDebugAttr>()) + return nullptr; + + // Skip the tuple like case, we don't handle that here + if (isa<DeclRefExpr>(BD->getBinding())) + return nullptr; + + llvm::DIType *Ty = CreateBindingDeclType(BD); + + // If there is no debug info for this type then do not emit debug info + // for this variable. + if (!Ty) + return nullptr; + + auto Align = getDeclAlignIfRequired(BD, CGM.getContext()); + unsigned AddressSpace = CGM.getTypes().getTargetAddressSpace(BD->getType()); + + SmallVector<uint64_t, 3> Expr; + AppendAddressSpaceXDeref(AddressSpace, Expr); + + // Clang stores the sret pointer provided by the caller in a static alloca. + // Use DW_OP_deref to tell the debugger to load the pointer and treat it as + // the address of the variable. + if (UsePointerValue) { + assert(!llvm::is_contained(Expr, llvm::dwarf::DW_OP_deref) && + "Debug info already contains DW_OP_deref."); + Expr.push_back(llvm::dwarf::DW_OP_deref); + } + + unsigned Line = getLineNumber(BD->getLocation()); + unsigned Column = getColumnNumber(BD->getLocation()); + StringRef Name = BD->getName(); + auto *Scope = cast<llvm::DIScope>(LexicalBlockStack.back()); + llvm::DIFile *Unit = getOrCreateFile(BD->getLocation()); + // Create the descriptor for the variable. + llvm::DILocalVariable *D = DBuilder.createAutoVariable( + Scope, Name, Unit, Line, Ty, CGM.getLangOpts().Optimize, + llvm::DINode::FlagZero, Align); + + if (const MemberExpr *ME = dyn_cast<MemberExpr>(BD->getBinding())) { + if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) { + const unsigned fieldIndex = FD->getFieldIndex(); + const clang::CXXRecordDecl *parent = + (const CXXRecordDecl *)FD->getParent(); + const ASTRecordLayout &layout = + CGM.getContext().getASTRecordLayout(parent); + const uint64_t fieldOffset = layout.getFieldOffset(fieldIndex); + + if (fieldOffset != 0) { + // Currently if the field offset is not a multiple of byte, the produced + // location would not be accurate. Therefore give up. + if (fieldOffset % CGM.getContext().getCharWidth() != 0) + return nullptr; + + Expr.push_back(llvm::dwarf::DW_OP_plus_uconst); + Expr.push_back( + CGM.getContext().toCharUnitsFromBits(fieldOffset).getQuantity()); + } + } + } else if (const ArraySubscriptExpr *ASE = + dyn_cast<ArraySubscriptExpr>(BD->getBinding())) { + if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(ASE->getIdx())) { + const uint64_t value = IL->getValue().getZExtValue(); + const uint64_t typeSize = CGM.getContext().getTypeSize(BD->getType()); + + if (value != 0) { + Expr.push_back(llvm::dwarf::DW_OP_plus_uconst); + Expr.push_back(CGM.getContext() + .toCharUnitsFromBits(value * typeSize) + .getQuantity()); + } + } + } + + // Insert an llvm.dbg.declare into the current block. + DBuilder.insertDeclare(Storage, D, DBuilder.createExpression(Expr), + llvm::DILocation::get(CGM.getLLVMContext(), Line, + Column, Scope, CurInlinedAt), + Builder.GetInsertBlock()); + + return D; +} + llvm::DILocalVariable * CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder, const bool UsePointerValue) { assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); - return EmitDeclare(VD, Storage, llvm::None, Builder, UsePointerValue); + + if (auto *DD = dyn_cast<DecompositionDecl>(VD)) { + for (auto *B : DD->bindings()) { + EmitDeclare(B, Storage, std::nullopt, Builder, + VD->getType()->isReferenceType()); + } + // Don't emit an llvm.dbg.declare for the composite storage as it doesn't + // correspond to a user variable. + return nullptr; + } + + return EmitDeclare(VD, Storage, std::nullopt, Builder, UsePointerValue); } void CGDebugInfo::EmitLabel(const LabelDecl *D, CGBuilderTy &Builder) { @@ -4467,7 +4972,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( // Self is passed along as an implicit non-arg variable in a // block. Mark it as the object pointer. if (const auto *IPD = dyn_cast<ImplicitParamDecl>(VD)) - if (IPD->getParameterKind() == ImplicitParamDecl::ObjCSelf) + if (IPD->getParameterKind() == ImplicitParamKind::ObjCSelf) Ty = CreateSelfType(VD->getType(), Ty); // Get location information. @@ -4481,7 +4986,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( target.getStructLayout(blockInfo.StructureType) ->getElementOffset(blockInfo.getCapture(VD).getIndex())); - SmallVector<int64_t, 9> addr; + SmallVector<uint64_t, 9> addr; addr.push_back(llvm::dwarf::DW_OP_deref); addr.push_back(llvm::dwarf::DW_OP_plus_uconst); addr.push_back(offset.getQuantity()); @@ -4517,9 +5022,10 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( llvm::DILocalVariable * CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, - unsigned ArgNo, CGBuilderTy &Builder) { + unsigned ArgNo, CGBuilderTy &Builder, + bool UsePointerValue) { assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); - return EmitDeclare(VD, AI, ArgNo, Builder); + return EmitDeclare(VD, AI, ArgNo, Builder, UsePointerValue); } namespace { @@ -4653,7 +5159,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, llvm::DIType *fieldType; if (capture->isByRef()) { TypeInfo PtrInfo = C.getTypeInfo(C.VoidPtrTy); - auto Align = PtrInfo.AlignIsRequired ? PtrInfo.Align : 0; + auto Align = PtrInfo.isAlignRequired() ? PtrInfo.Align : 0; // FIXME: This recomputes the layout of the BlockByRefWrapper. uint64_t xoffset; fieldType = @@ -4740,14 +5246,231 @@ llvm::DIGlobalVariableExpression *CGDebugInfo::CollectAnonRecordDecls( return GVE; } +static bool ReferencesAnonymousEntity(ArrayRef<TemplateArgument> Args); +static bool ReferencesAnonymousEntity(RecordType *RT) { + // Unnamed classes/lambdas can't be reconstituted due to a lack of column + // info we produce in the DWARF, so we can't get Clang's full name back. + // But so long as it's not one of those, it doesn't matter if some sub-type + // of the record (a template parameter) can't be reconstituted - because the + // un-reconstitutable type itself will carry its own name. + const auto *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD) + return false; + if (!RD->getIdentifier()) + return true; + auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD); + if (!TSpecial) + return false; + return ReferencesAnonymousEntity(TSpecial->getTemplateArgs().asArray()); +} +static bool ReferencesAnonymousEntity(ArrayRef<TemplateArgument> Args) { + return llvm::any_of(Args, [&](const TemplateArgument &TA) { + switch (TA.getKind()) { + case TemplateArgument::Pack: + return ReferencesAnonymousEntity(TA.getPackAsArray()); + case TemplateArgument::Type: { + struct ReferencesAnonymous + : public RecursiveASTVisitor<ReferencesAnonymous> { + bool RefAnon = false; + bool VisitRecordType(RecordType *RT) { + if (ReferencesAnonymousEntity(RT)) { + RefAnon = true; + return false; + } + return true; + } + }; + ReferencesAnonymous RT; + RT.TraverseType(TA.getAsType()); + if (RT.RefAnon) + return true; + break; + } + default: + break; + } + return false; + }); +} +namespace { +struct ReconstitutableType : public RecursiveASTVisitor<ReconstitutableType> { + bool Reconstitutable = true; + bool VisitVectorType(VectorType *FT) { + Reconstitutable = false; + return false; + } + bool VisitAtomicType(AtomicType *FT) { + Reconstitutable = false; + return false; + } + bool VisitType(Type *T) { + // _BitInt(N) isn't reconstitutable because the bit width isn't encoded in + // the DWARF, only the byte width. + if (T->isBitIntType()) { + Reconstitutable = false; + return false; + } + return true; + } + bool TraverseEnumType(EnumType *ET) { + // Unnamed enums can't be reconstituted due to a lack of column info we + // produce in the DWARF, so we can't get Clang's full name back. + if (const auto *ED = dyn_cast<EnumDecl>(ET->getDecl())) { + if (!ED->getIdentifier()) { + Reconstitutable = false; + return false; + } + if (!ED->isExternallyVisible()) { + Reconstitutable = false; + return false; + } + } + return true; + } + bool VisitFunctionProtoType(FunctionProtoType *FT) { + // noexcept is not encoded in DWARF, so the reversi + Reconstitutable &= !isNoexceptExceptionSpec(FT->getExceptionSpecType()); + Reconstitutable &= !FT->getNoReturnAttr(); + return Reconstitutable; + } + bool VisitRecordType(RecordType *RT) { + if (ReferencesAnonymousEntity(RT)) { + Reconstitutable = false; + return false; + } + return true; + } +}; +} // anonymous namespace + +// Test whether a type name could be rebuilt from emitted debug info. +static bool IsReconstitutableType(QualType QT) { + ReconstitutableType T; + T.TraverseType(QT); + return T.Reconstitutable; +} + std::string CGDebugInfo::GetName(const Decl *D, bool Qualified) const { std::string Name; llvm::raw_string_ostream OS(Name); - if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { - PrintingPolicy PP = getPrintingPolicy(); - PP.PrintCanonicalTypes = true; - PP.SuppressInlineNamespace = false; + const NamedDecl *ND = dyn_cast<NamedDecl>(D); + if (!ND) + return Name; + llvm::codegenoptions::DebugTemplateNamesKind TemplateNamesKind = + CGM.getCodeGenOpts().getDebugSimpleTemplateNames(); + + if (!CGM.getCodeGenOpts().hasReducedDebugInfo()) + TemplateNamesKind = llvm::codegenoptions::DebugTemplateNamesKind::Full; + + std::optional<TemplateArgs> Args; + + bool IsOperatorOverload = false; // isa<CXXConversionDecl>(ND); + if (auto *RD = dyn_cast<CXXRecordDecl>(ND)) { + Args = GetTemplateArgs(RD); + } else if (auto *FD = dyn_cast<FunctionDecl>(ND)) { + Args = GetTemplateArgs(FD); + auto NameKind = ND->getDeclName().getNameKind(); + IsOperatorOverload |= + NameKind == DeclarationName::CXXOperatorName || + NameKind == DeclarationName::CXXConversionFunctionName; + } else if (auto *VD = dyn_cast<VarDecl>(ND)) { + Args = GetTemplateArgs(VD); + } + std::function<bool(ArrayRef<TemplateArgument>)> HasReconstitutableArgs = + [&](ArrayRef<TemplateArgument> Args) { + return llvm::all_of(Args, [&](const TemplateArgument &TA) { + switch (TA.getKind()) { + case TemplateArgument::Template: + // Easy to reconstitute - the value of the parameter in the debug + // info is the string name of the template. (so the template name + // itself won't benefit from any name rebuilding, but that's a + // representational limitation - maybe DWARF could be + // changed/improved to use some more structural representation) + return true; + case TemplateArgument::Declaration: + // Reference and pointer non-type template parameters point to + // variables, functions, etc and their value is, at best (for + // variables) represented as an address - not a reference to the + // DWARF describing the variable/function/etc. This makes it hard, + // possibly impossible to rebuild the original name - looking up the + // address in the executable file's symbol table would be needed. + return false; + case TemplateArgument::NullPtr: + // These could be rebuilt, but figured they're close enough to the + // declaration case, and not worth rebuilding. + return false; + case TemplateArgument::Pack: + // A pack is invalid if any of the elements of the pack are invalid. + return HasReconstitutableArgs(TA.getPackAsArray()); + case TemplateArgument::Integral: + // Larger integers get encoded as DWARF blocks which are a bit + // harder to parse back into a large integer, etc - so punting on + // this for now. Re-parsing the integers back into APInt is probably + // feasible some day. + return TA.getAsIntegral().getBitWidth() <= 64 && + IsReconstitutableType(TA.getIntegralType()); + case TemplateArgument::StructuralValue: + return false; + case TemplateArgument::Type: + return IsReconstitutableType(TA.getAsType()); + default: + llvm_unreachable("Other, unresolved, template arguments should " + "not be seen here"); + } + }); + }; + // A conversion operator presents complications/ambiguity if there's a + // conversion to class template that is itself a template, eg: + // template<typename T> + // operator ns::t1<T, int>(); + // This should be named, eg: "operator ns::t1<float, int><float>" + // (ignoring clang bug that means this is currently "operator t1<float>") + // but if the arguments were stripped, the consumer couldn't differentiate + // whether the template argument list for the conversion type was the + // function's argument list (& no reconstitution was needed) or not. + // This could be handled if reconstitutable names had a separate attribute + // annotating them as such - this would remove the ambiguity. + // + // Alternatively the template argument list could be parsed enough to check + // whether there's one list or two, then compare that with the DWARF + // description of the return type and the template argument lists to determine + // how many lists there should be and if one is missing it could be assumed(?) + // to be the function's template argument list & then be rebuilt. + // + // Other operator overloads that aren't conversion operators could be + // reconstituted but would require a bit more nuance about detecting the + // difference between these different operators during that rebuilding. + bool Reconstitutable = + Args && HasReconstitutableArgs(Args->Args) && !IsOperatorOverload; + + PrintingPolicy PP = getPrintingPolicy(); + + if (TemplateNamesKind == llvm::codegenoptions::DebugTemplateNamesKind::Full || + !Reconstitutable) { ND->getNameForDiagnostic(OS, PP, Qualified); + } else { + bool Mangled = TemplateNamesKind == + llvm::codegenoptions::DebugTemplateNamesKind::Mangled; + // check if it's a template + if (Mangled) + OS << "_STN|"; + + OS << ND->getDeclName(); + std::string EncodedOriginalName; + llvm::raw_string_ostream EncodedOriginalNameOS(EncodedOriginalName); + EncodedOriginalNameOS << ND->getDeclName(); + + if (Mangled) { + OS << "|"; + printTemplateArgumentList(OS, Args->Args, PP); + printTemplateArgumentList(EncodedOriginalNameOS, Args->Args, PP); +#ifndef NDEBUG + std::string CanonicalOriginalName; + llvm::raw_string_ostream OriginalOS(CanonicalOriginalName); + ND->getNameForDiagnostic(OriginalOS, PP, Qualified); + assert(EncodedOriginalNameOS.str() == OriginalOS.str()); +#endif + } } return Name; } @@ -4794,9 +5517,8 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, } else { auto Align = getDeclAlignIfRequired(D, CGM.getContext()); - SmallVector<int64_t, 4> Expr; - unsigned AddressSpace = - CGM.getContext().getTargetAddressSpace(D->getType()); + SmallVector<uint64_t, 4> Expr; + unsigned AddressSpace = CGM.getTypes().getTargetAddressSpace(D->getType()); if (CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) { if (D->hasAttr<CUDASharedAttr>()) AddressSpace = @@ -4807,12 +5529,13 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, } AppendAddressSpaceXDeref(AddressSpace, Expr); + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D); GVE = DBuilder.createGlobalVariableExpression( DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit), Var->hasLocalLinkage(), true, Expr.empty() ? nullptr : DBuilder.createExpression(Expr), getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters, - Align); + Align, Annotations); Var->addDebugInfo(GVE); } DeclCache[D->getCanonicalDecl()].reset(GVE); @@ -4878,17 +5601,8 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) { auto &GV = DeclCache[VD]; if (GV) return; - llvm::DIExpression *InitExpr = nullptr; - if (CGM.getContext().getTypeSize(VD->getType()) <= 64) { - // FIXME: Add a representation for integer constants wider than 64 bits. - if (Init.isInt()) - InitExpr = - DBuilder.createConstantValueExpression(Init.getInt().getExtValue()); - else if (Init.isFloat()) - InitExpr = DBuilder.createConstantValueExpression( - Init.getFloat().bitcastToAPInt().getZExtValue()); - } + llvm::DIExpression *InitExpr = createConstantValueExpression(VD, Init); llvm::MDTuple *TemplateParameters = nullptr; if (isa<VarTemplateSpecializationDecl>(VD)) @@ -4922,6 +5636,62 @@ void CGDebugInfo::EmitExternalVariable(llvm::GlobalVariable *Var, Var->addDebugInfo(GVE); } +void CGDebugInfo::EmitGlobalAlias(const llvm::GlobalValue *GV, + const GlobalDecl GD) { + + assert(GV); + + if (!CGM.getCodeGenOpts().hasReducedDebugInfo()) + return; + + const auto *D = cast<ValueDecl>(GD.getDecl()); + if (D->hasAttr<NoDebugAttr>()) + return; + + auto AliaseeDecl = CGM.getMangledNameDecl(GV->getName()); + llvm::DINode *DI; + + if (!AliaseeDecl) + // FIXME: Aliasee not declared yet - possibly declared later + // For example, + // + // 1 extern int newname __attribute__((alias("oldname"))); + // 2 int oldname = 1; + // + // No debug info would be generated for 'newname' in this case. + // + // Fix compiler to generate "newname" as imported_declaration + // pointing to the DIE of "oldname". + return; + if (!(DI = getDeclarationOrDefinition( + AliaseeDecl.getCanonicalDecl().getDecl()))) + return; + + llvm::DIScope *DContext = getDeclContextDescriptor(D); + auto Loc = D->getLocation(); + + llvm::DIImportedEntity *ImportDI = DBuilder.createImportedDeclaration( + DContext, DI, getOrCreateFile(Loc), getLineNumber(Loc), D->getName()); + + // Record this DIE in the cache for nested declaration reference. + ImportedDeclCache[GD.getCanonicalDecl().getDecl()].reset(ImportDI); +} + +void CGDebugInfo::AddStringLiteralDebugInfo(llvm::GlobalVariable *GV, + const StringLiteral *S) { + SourceLocation Loc = S->getStrTokenLoc(0); + PresumedLoc PLoc = CGM.getContext().getSourceManager().getPresumedLoc(Loc); + if (!PLoc.isValid()) + return; + + llvm::DIFile *File = getOrCreateFile(Loc); + llvm::DIGlobalVariableExpression *Debug = + DBuilder.createGlobalVariableExpression( + nullptr, StringRef(), StringRef(), getOrCreateFile(Loc), + getLineNumber(Loc), getOrCreateType(S->getType(), File), true); + GV->addDebugInfo(Debug); +} + llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) { if (!LexicalBlockStack.empty()) return LexicalBlockStack.back(); @@ -5151,8 +5921,9 @@ llvm::DebugLoc CGDebugInfo::SourceLocToDebugLoc(SourceLocation Loc) { llvm::DINode::DIFlags CGDebugInfo::getCallSiteRelatedAttrs() const { // Call site-related attributes are only useful in optimized programs, and // when there's a possibility of debugging backtraces. - if (!CGM.getLangOpts().Optimize || DebugKind == codegenoptions::NoDebugInfo || - DebugKind == codegenoptions::LocTrackingOnly) + if (!CGM.getLangOpts().Optimize || + DebugKind == llvm::codegenoptions::NoDebugInfo || + DebugKind == llvm::codegenoptions::LocTrackingOnly) return llvm::DINode::FlagZero; // Call site-related attributes are available in DWARF v5. Some debuggers, @@ -5168,3 +5939,32 @@ llvm::DINode::DIFlags CGDebugInfo::getCallSiteRelatedAttrs() const { return llvm::DINode::FlagAllCallsDescribed; } + +llvm::DIExpression * +CGDebugInfo::createConstantValueExpression(const clang::ValueDecl *VD, + const APValue &Val) { + // FIXME: Add a representation for integer constants wider than 64 bits. + if (CGM.getContext().getTypeSize(VD->getType()) > 64) + return nullptr; + + if (Val.isFloat()) + return DBuilder.createConstantValueExpression( + Val.getFloat().bitcastToAPInt().getZExtValue()); + + if (!Val.isInt()) + return nullptr; + + llvm::APSInt const &ValInt = Val.getInt(); + std::optional<uint64_t> ValIntOpt; + if (ValInt.isUnsigned()) + ValIntOpt = ValInt.tryZExtValue(); + else if (auto tmp = ValInt.trySExtValue()) + // Transform a signed optional to unsigned optional. When cpp 23 comes, + // use std::optional::transform + ValIntOpt = static_cast<uint64_t>(*tmp); + + if (ValIntOpt) + return DBuilder.createConstantValueExpression(ValIntOpt.value()); + + return nullptr; +} |