Recommit "[CodeView] Emit static data members as S_CONSTANTs."

We used to only emit static const data members in CodeView as
S_CONSTANTS when they were used; this patch makes it so they are always emitted.

This changes CodeViewDebug.cpp to find the static const members from the
class debug info instead of creating DIGlobalVariables in the IR
whenever a static const data member is used.

Bug: https://bugs.llvm.org/show_bug.cgi?id=47580

Differential Revision: https://reviews.llvm.org/D89072

This reverts commit 504615353f.
This commit is contained in:
Amy Huang 2020-10-27 11:35:57 -07:00
parent de51867343
commit 7669f3c0f6
10 changed files with 198 additions and 146 deletions

View File

@ -4736,13 +4736,10 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) {
}
}
llvm::DIScope *DContext = nullptr;
// Do not emit separate definitions for function local consts.
if (isa<FunctionDecl>(VD->getDeclContext()))
return;
// Emit definition for static members in CodeView.
VD = cast<ValueDecl>(VD->getCanonicalDecl());
auto *VarD = dyn_cast<VarDecl>(VD);
if (VarD && VarD->isStaticDataMember()) {
@ -4755,15 +4752,9 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) {
RetainedTypes.push_back(
CGM.getContext().getRecordType(RD).getAsOpaquePtr());
if (!CGM.getCodeGenOpts().EmitCodeView)
return;
// Use the global scope for static members.
DContext = getContextDescriptor(
cast<Decl>(CGM.getContext().getTranslationUnitDecl()), TheCU);
} else {
DContext = getDeclContextDescriptor(VD);
return;
}
llvm::DIScope *DContext = getDeclContextDescriptor(VD);
auto &GV = DeclCache[VD];
if (GV)

View File

@ -1,12 +1,12 @@
// RUN: %clangxx -target x86_64-unknown-unknown -g %s -emit-llvm -S -o - | FileCheck %s
// RUN: %clangxx -target x86_64-unknown-unknown -g -std=c++98 %s -emit-llvm -S -o - | FileCheck %s
// RUN: %clangxx -target x86_64-unknown-unknown -g -std=c++11 %s -emit-llvm -S -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-windows-msvc -gcodeview -debug-info-kind=limited %s -emit-llvm -o - | FileCheck --check-prefix MSVC %s
// RUN: %clangxx -target x86_64-unknown-unknown -g %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK,NOT-MS %s
// RUN: %clangxx -target x86_64-unknown-unknown -g -std=c++98 %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK,NOT-MS %s
// RUN: %clangxx -target x86_64-unknown-unknown -g -std=c++11 %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK,NOT-MS %s
// RUN: %clangxx -target x86_64-windows-msvc -g %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK %s
// PR14471
// CHECK: @_ZN1C1aE = dso_local global i32 4, align 4, !dbg [[A:![0-9]+]]
// CHECK: @_ZN1C1bE = dso_local global i32 2, align 4, !dbg [[B:![0-9]+]]
// CHECK: @_ZN1C1cE = dso_local global i32 1, align 4, !dbg [[C:![0-9]+]]
// CHECK: @{{.*}}a{{.*}} = dso_local global i32 4, align 4, !dbg [[A:![0-9]+]]
// CHECK: @{{.*}}b{{.*}} = dso_local global i32 2, align 4, !dbg [[B:![0-9]+]]
// CHECK: @{{.*}}c{{.*}} = dso_local global i32 1, align 4, !dbg [[C:![0-9]+]]
enum X {
Y
@ -36,9 +36,8 @@ public:
// CHECK: [[A]] = !DIGlobalVariableExpression(var: [[AV:.*]], expr: !DIExpression())
// CHECK: [[AV]] = distinct !DIGlobalVariable(name: "a",
// CHECK-SAME: declaration: ![[DECL_A:[0-9]+]])
// MSVC: distinct !DIGlobalVariable(name: "a"
//
// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "X"{{.*}}, identifier: "_ZTS1X")
// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "X"{{.*}})
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "anon_static_decl_struct"
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "anon_static_decl_var"
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "static_decl_templ<int>"
@ -50,14 +49,13 @@ int C::a = 4;
// CHECK: [[B]] = !DIGlobalVariableExpression(var: [[BV:.*]], expr: !DIExpression())
// CHECK: [[BV]] = distinct !DIGlobalVariable(name: "b",
// CHECK-SAME: declaration: ![[DECL_B:[0-9]+]])
// MSVC: distinct !DIGlobalVariable(name: "b"
// CHECK: ![[DECL_B]] = !DIDerivedType(tag: DW_TAG_member, name: "b"
// CHECK-NOT: size:
// CHECK-NOT: align:
// CHECK-NOT: offset:
// CHECK-SAME: flags: DIFlagProtected | DIFlagStaticMember)
//
// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "C"{{.*}}, identifier: "_ZTS1C")
// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "C"{{.*}})
//
// CHECK: ![[DECL_A]] = !DIDerivedType(tag: DW_TAG_member, name: "a"
// CHECK-NOT: size:
@ -98,7 +96,6 @@ int C::a = 4;
int C::b = 2;
// CHECK: [[C]] = !DIGlobalVariableExpression(var: [[CV:.*]], expr: !DIExpression())
// CHECK: [[CV]] = distinct !DIGlobalVariable(name: "c", {{.*}} declaration: ![[DECL_C]])
// MSVC: distinct !DIGlobalVariable(name: "c"
int C::c = 1;
int main()
@ -122,14 +119,6 @@ int ref() {
return anon_static_decl_struct::anon_static_decl_var;
}
// In MSVC, static data members should be emitted as global variables when used.
// MSVC: !DIGlobalVariableExpression(var: [[ANON_STATIC_DECL:![0-9]+]],
// MSVC-SAME: !DIExpression(DW_OP_constu, 117, DW_OP_stack_value)
// MSVC: [[ANON_STATIC_DECL]] = distinct !DIGlobalVariable(name: "anon_static_decl_var"
// MSVC: !DIGlobalVariableExpression(var: [[STATIC_DECL_TEMPL:![0-9]+]]
// MSVC-SAME: !DIExpression(DW_OP_constu, 7, DW_OP_stack_value)
// MSVC: [[STATIC_DECL_TEMPL]] = distinct !DIGlobalVariable(name: "static_decl_templ_var"
template<typename T>
struct static_decl_templ {
static const int static_decl_templ_var = 7;
@ -151,9 +140,11 @@ struct V {
virtual ~V(); // cause the definition of 'V' to be omitted by no-standalone-debug optimization
static const int const_va = 42;
};
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "const_va",
// CHECK-SAME: line: [[@LINE-3]]
// CHECK-SAME: extraData: i32 42
// const_va is not emitted for MS targets.
// NOT-MS: !DIDerivedType(tag: DW_TAG_member, name: "const_va",
// NOT-MS-SAME: line: [[@LINE-5]]
// NOT-MS-SAME: extraData: i32 42
const int V::const_va;
namespace x {

View File

@ -133,6 +133,9 @@ public:
/// If this type is derived from a base type then return base type size.
static uint64_t getBaseTypeSize(const DIType *Ty);
/// Return true if type encoding is unsigned.
static bool isUnsignedDIType(const DIType *Ty);
const InstructionOrdering &getInstOrdering() const { return InstOrdering; }
};

View File

@ -588,13 +588,18 @@ void CodeViewDebug::endModule() {
if (!P.first->isDeclarationForLinker())
emitDebugInfoForFunction(P.first, *P.second);
// Emit global variable debug information.
setCurrentSubprogram(nullptr);
emitDebugInfoForGlobals();
// Get types used by globals without emitting anything.
// This is meant to collect all static const data members so they can be
// emitted as globals.
collectDebugInfoForGlobals();
// Emit retained types.
emitDebugInfoForRetainedTypes();
// Emit global variable debug information.
setCurrentSubprogram(nullptr);
emitDebugInfoForGlobals();
// Switch back to the generic .debug$S section after potentially processing
// comdat symbol sections.
switchToDebugSectionForSymbol(nullptr);
@ -2143,6 +2148,12 @@ void CodeViewDebug::collectMemberInfo(ClassInfo &Info,
const DIDerivedType *DDTy) {
if (!DDTy->getName().empty()) {
Info.Members.push_back({DDTy, 0});
// Collect static const data members.
if ((DDTy->getFlags() & DINode::FlagStaticMember) ==
DINode::FlagStaticMember)
StaticConstMembers.push_back(DDTy);
return;
}
@ -3045,15 +3056,32 @@ void CodeViewDebug::collectGlobalVariableInfo() {
}
}
void CodeViewDebug::collectDebugInfoForGlobals() {
for (const CVGlobalVariable &CVGV : GlobalVariables) {
const DIGlobalVariable *DIGV = CVGV.DIGV;
const DIScope *Scope = DIGV->getScope();
getCompleteTypeIndex(DIGV->getType());
getFullyQualifiedName(Scope, DIGV->getName());
}
for (const CVGlobalVariable &CVGV : ComdatVariables) {
const DIGlobalVariable *DIGV = CVGV.DIGV;
const DIScope *Scope = DIGV->getScope();
getCompleteTypeIndex(DIGV->getType());
getFullyQualifiedName(Scope, DIGV->getName());
}
}
void CodeViewDebug::emitDebugInfoForGlobals() {
// First, emit all globals that are not in a comdat in a single symbol
// substream. MSVC doesn't like it if the substream is empty, so only open
// it if we have at least one global to emit.
switchToDebugSectionForSymbol(nullptr);
if (!GlobalVariables.empty()) {
if (!GlobalVariables.empty() || !StaticConstMembers.empty()) {
OS.AddComment("Symbol subsection for globals");
MCSymbol *EndLabel = beginCVSubsection(DebugSubsectionKind::Symbols);
emitGlobalVariableList(GlobalVariables);
emitStaticConstMemberList();
endCVSubsection(EndLabel);
}
@ -3092,6 +3120,42 @@ void CodeViewDebug::emitGlobalVariableList(ArrayRef<CVGlobalVariable> Globals) {
}
}
void CodeViewDebug::emitStaticConstMemberList() {
for (const DIDerivedType *DTy : StaticConstMembers) {
const DIScope *Scope = DTy->getScope();
APSInt Value;
if (const ConstantInt *CI =
dyn_cast_or_null<ConstantInt>(DTy->getConstant()))
Value = APSInt(CI->getValue(),
DebugHandlerBase::isUnsignedDIType(DTy->getBaseType()));
else if (const ConstantFP *CFP =
dyn_cast_or_null<ConstantFP>(DTy->getConstant()))
Value = APSInt(CFP->getValueAPF().bitcastToAPInt(), true);
else
continue;
std::string QualifiedName = getFullyQualifiedName(Scope, DTy->getName());
MCSymbol *SConstantEnd = beginSymbolRecord(SymbolKind::S_CONSTANT);
OS.AddComment("Type");
OS.emitInt32(getTypeIndex(DTy->getBaseType()).getIndex());
OS.AddComment("Value");
// Encoded integers shouldn't need more than 10 bytes.
uint8_t Data[10];
BinaryStreamWriter Writer(Data, llvm::support::endianness::little);
CodeViewRecordIO IO(Writer);
cantFail(IO.mapEncodedInteger(Value));
StringRef SRef((char *)Data, Writer.getOffset());
OS.emitBinaryData(SRef);
OS.AddComment("Name");
emitNullTerminatedSymbolName(OS, QualifiedName);
endSymbolRecord(SConstantEnd);
}
}
void CodeViewDebug::emitDebugInfoForGlobal(const CVGlobalVariable &CVGV) {
const DIGlobalVariable *DIGV = CVGV.DIGV;

View File

@ -203,6 +203,9 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
// Array of non-COMDAT global variables.
SmallVector<CVGlobalVariable, 1> GlobalVariables;
/// List of static const data members to be emitted as S_CONSTANTs.
SmallVector<const DIDerivedType *, 4> StaticConstMembers;
/// The set of comdat .debug$S sections that we've seen so far. Each section
/// must start with a magic version number that must only be emitted once.
/// This set tracks which sections we've already opened.
@ -313,9 +316,11 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
void emitDebugInfoForUDTs(
const std::vector<std::pair<std::string, const DIType *>> &UDTs);
void collectDebugInfoForGlobals();
void emitDebugInfoForGlobals();
void emitGlobalVariableList(ArrayRef<CVGlobalVariable> Globals);
void emitDebugInfoForGlobal(const CVGlobalVariable &CVGV);
void emitStaticConstMemberList();
/// Opens a subsection of the given kind in a .debug$S codeview section.
/// Returns an end label for use with endCVSubsection when the subsection is

View File

@ -158,6 +158,54 @@ uint64_t DebugHandlerBase::getBaseTypeSize(const DIType *Ty) {
return getBaseTypeSize(BaseType);
}
bool DebugHandlerBase::isUnsignedDIType(const DIType *Ty) {
if (auto *CTy = dyn_cast<DICompositeType>(Ty)) {
// FIXME: Enums without a fixed underlying type have unknown signedness
// here, leading to incorrectly emitted constants.
if (CTy->getTag() == dwarf::DW_TAG_enumeration_type)
return false;
// (Pieces of) aggregate types that get hacked apart by SROA may be
// represented by a constant. Encode them as unsigned bytes.
return true;
}
if (auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
dwarf::Tag T = (dwarf::Tag)Ty->getTag();
// Encode pointer constants as unsigned bytes. This is used at least for
// null pointer constant emission.
// FIXME: reference and rvalue_reference /probably/ shouldn't be allowed
// here, but accept them for now due to a bug in SROA producing bogus
// dbg.values.
if (T == dwarf::DW_TAG_pointer_type ||
T == dwarf::DW_TAG_ptr_to_member_type ||
T == dwarf::DW_TAG_reference_type ||
T == dwarf::DW_TAG_rvalue_reference_type)
return true;
assert(T == dwarf::DW_TAG_typedef || T == dwarf::DW_TAG_const_type ||
T == dwarf::DW_TAG_volatile_type ||
T == dwarf::DW_TAG_restrict_type || T == dwarf::DW_TAG_atomic_type);
assert(DTy->getBaseType() && "Expected valid base type");
return isUnsignedDIType(DTy->getBaseType());
}
auto *BTy = cast<DIBasicType>(Ty);
unsigned Encoding = BTy->getEncoding();
assert((Encoding == dwarf::DW_ATE_unsigned ||
Encoding == dwarf::DW_ATE_unsigned_char ||
Encoding == dwarf::DW_ATE_signed ||
Encoding == dwarf::DW_ATE_signed_char ||
Encoding == dwarf::DW_ATE_float || Encoding == dwarf::DW_ATE_UTF ||
Encoding == dwarf::DW_ATE_boolean ||
(Ty->getTag() == dwarf::DW_TAG_unspecified_type &&
Ty->getName() == "decltype(nullptr)")) &&
"Unsupported encoding");
return Encoding == dwarf::DW_ATE_unsigned ||
Encoding == dwarf::DW_ATE_unsigned_char ||
Encoding == dwarf::DW_ATE_UTF || Encoding == dwarf::DW_ATE_boolean ||
Ty->getTag() == dwarf::DW_TAG_unspecified_type;
}
static bool hasDebugInfo(const MachineModuleInfo *MMI,
const MachineFunction *MF) {
if (!MMI->hasDebugInfo())

View File

@ -434,55 +434,6 @@ void DwarfUnit::addSourceLine(DIE &Die, const DIObjCProperty *Ty) {
addSourceLine(Die, Ty->getLine(), Ty->getFile());
}
/// Return true if type encoding is unsigned.
static bool isUnsignedDIType(DwarfDebug *DD, const DIType *Ty) {
if (auto *CTy = dyn_cast<DICompositeType>(Ty)) {
// FIXME: Enums without a fixed underlying type have unknown signedness
// here, leading to incorrectly emitted constants.
if (CTy->getTag() == dwarf::DW_TAG_enumeration_type)
return false;
// (Pieces of) aggregate types that get hacked apart by SROA may be
// represented by a constant. Encode them as unsigned bytes.
return true;
}
if (auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
dwarf::Tag T = (dwarf::Tag)Ty->getTag();
// Encode pointer constants as unsigned bytes. This is used at least for
// null pointer constant emission.
// FIXME: reference and rvalue_reference /probably/ shouldn't be allowed
// here, but accept them for now due to a bug in SROA producing bogus
// dbg.values.
if (T == dwarf::DW_TAG_pointer_type ||
T == dwarf::DW_TAG_ptr_to_member_type ||
T == dwarf::DW_TAG_reference_type ||
T == dwarf::DW_TAG_rvalue_reference_type)
return true;
assert(T == dwarf::DW_TAG_typedef || T == dwarf::DW_TAG_const_type ||
T == dwarf::DW_TAG_volatile_type ||
T == dwarf::DW_TAG_restrict_type || T == dwarf::DW_TAG_atomic_type);
assert(DTy->getBaseType() && "Expected valid base type");
return isUnsignedDIType(DD, DTy->getBaseType());
}
auto *BTy = cast<DIBasicType>(Ty);
unsigned Encoding = BTy->getEncoding();
assert((Encoding == dwarf::DW_ATE_unsigned ||
Encoding == dwarf::DW_ATE_unsigned_char ||
Encoding == dwarf::DW_ATE_signed ||
Encoding == dwarf::DW_ATE_signed_char ||
Encoding == dwarf::DW_ATE_float || Encoding == dwarf::DW_ATE_UTF ||
Encoding == dwarf::DW_ATE_boolean ||
(Ty->getTag() == dwarf::DW_TAG_unspecified_type &&
Ty->getName() == "decltype(nullptr)")) &&
"Unsupported encoding");
return Encoding == dwarf::DW_ATE_unsigned ||
Encoding == dwarf::DW_ATE_unsigned_char ||
Encoding == dwarf::DW_ATE_UTF || Encoding == dwarf::DW_ATE_boolean ||
Ty->getTag() == dwarf::DW_TAG_unspecified_type;
}
void DwarfUnit::addConstantFPValue(DIE &Die, const MachineOperand &MO) {
assert(MO.isFPImm() && "Invalid machine operand!");
DIEBlock *Block = new (DIEValueAllocator) DIEBlock;
@ -519,11 +470,11 @@ void DwarfUnit::addConstantValue(DIE &Die, const MachineOperand &MO,
const DIType *Ty) {
assert(MO.isImm() && "Invalid machine operand!");
addConstantValue(Die, isUnsignedDIType(DD, Ty), MO.getImm());
addConstantValue(Die, DD->isUnsignedDIType(Ty), MO.getImm());
}
void DwarfUnit::addConstantValue(DIE &Die, uint64_t Val, const DIType *Ty) {
addConstantValue(Die, isUnsignedDIType(DD, Ty), Val);
addConstantValue(Die, DD->isUnsignedDIType(Ty), Val);
}
void DwarfUnit::addConstantValue(DIE &Die, bool Unsigned, uint64_t Val) {
@ -534,7 +485,7 @@ void DwarfUnit::addConstantValue(DIE &Die, bool Unsigned, uint64_t Val) {
}
void DwarfUnit::addConstantValue(DIE &Die, const APInt &Val, const DIType *Ty) {
addConstantValue(Die, Val, isUnsignedDIType(DD, Ty));
addConstantValue(Die, Val, DD->isUnsignedDIType(Ty));
}
void DwarfUnit::addConstantValue(DIE &Die, const APInt &Val, bool Unsigned) {
@ -936,7 +887,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
DIE &Variant = createAndAddDIE(dwarf::DW_TAG_variant, Buffer);
if (const ConstantInt *CI =
dyn_cast_or_null<ConstantInt>(DDTy->getDiscriminantValue())) {
if (isUnsignedDIType(DD, Discriminator->getBaseType()))
if (DD->isUnsignedDIType(Discriminator->getBaseType()))
addUInt(Variant, dwarf::DW_AT_discr_value, None, CI->getZExtValue());
else
addSInt(Variant, dwarf::DW_AT_discr_value, None, CI->getSExtValue());
@ -1543,7 +1494,7 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
void DwarfUnit::constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
const DIType *DTy = CTy->getBaseType();
bool IsUnsigned = DTy && isUnsignedDIType(DD, DTy);
bool IsUnsigned = DTy && DD->isUnsignedDIType(DTy);
if (DTy) {
if (DD->getDwarfVersion() >= 3)
addType(Buffer, DTy);

View File

@ -273,7 +273,6 @@ Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value,
void CodeViewRecordIO::emitEncodedSignedInteger(const int64_t &Value,
const Twine &Comment) {
assert(Value < 0 && "Encoded integer is not signed!");
if (Value >= std::numeric_limits<int8_t>::min()) {
Streamer->emitIntValue(LF_CHAR, 2);
emitComment(Comment);
@ -322,7 +321,6 @@ void CodeViewRecordIO::emitEncodedUnsignedInteger(const uint64_t &Value,
}
Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) {
assert(Value < 0 && "Encoded integer is not signed!");
if (Value >= std::numeric_limits<int8_t>::min()) {
if (auto EC = Writer->writeInteger<uint16_t>(LF_CHAR))
return EC;

View File

@ -7,6 +7,9 @@
; }
; struct S {
; static const int TestConst2 = -10;
; // Unused static consts should still be emitted.
; static const int TestConst3 = 3;
; static constexpr int TestConst 4 = 4;
; enum { SEnum = 42 };
; };
; enum TestEnum : int {
@ -34,14 +37,6 @@
; ASM: .short 4359 # Record kind: S_CONSTANT
; ASM-NEXT: .long 4101 # Type
; ASM-NEXT: .byte 0x0a, 0x80, 0xf6, 0xff # Value
; ASM-NEXT: .byte 0xff, 0xff, 0xff, 0xff
; ASM-NEXT: .byte 0xff, 0xff
; ASM-NEXT: .asciz "S::TestConst2" # Name
; ASM-NEXT: .p2align 2
; ASM: .short 4359 # Record kind: S_CONSTANT
; ASM-NEXT: .long 4110 # Type
; ASM-NEXT: .byte 0x0a, 0x80, 0x40, 0x61 # Value
; ASM-NEXT: .byte 0x07, 0x80, 0xff, 0xff
; ASM-NEXT: .byte 0xff, 0xff
@ -49,6 +44,12 @@
; ASM-NEXT: .p2align 2
; ASM-NOT: .asciz "S::SEnum" # Name
; ASM: .short 4359 # Record kind: S_CONSTANT
; ASM-NEXT: .long 4105 # Type
; ASM-NEXT: .byte 0x00, 0x80, 0xf6 # Value
; ASM-NEXT: .asciz "S::TestConst2" # Name
; ASM-NEXT: .p2align 2
; OBJ: CodeViewDebugInfo [
; OBJ: Section: .debug$S
; OBJ: Magic: 0x4
@ -62,17 +63,17 @@
; OBJ-NEXT: }
; OBJ-NEXT: ConstantSym {
; OBJ-NEXT: Kind: S_CONSTANT (0x1107)
; OBJ-NEXT: Type: const int (0x1005)
; OBJ-NEXT: Value: 18446744073709551606
; OBJ-NEXT: Name: S::TestConst2
; OBJ-NEXT: }
; OBJ-NEXT: ConstantSym {
; OBJ-NEXT: Kind: S_CONSTANT (0x1107)
; OBJ-NEXT: Type: TestEnum (0x100E)
; OBJ-NEXT: Type: TestEnum (0x1005)
; OBJ-NEXT: Value: 18446744071562551616
; OBJ-NEXT: Name: ENUM_B
; OBJ-NEXT: }
; OBJ-NOT: Name: S::SEnum
; OBJ-NEXT: ConstantSym {
; OBJ-NEXT: Kind: S_CONSTANT (0x1107)
; OBJ-NEXT: Type: const int (0x1009)
; OBJ-NEXT: Value: -10
; OBJ-NEXT: Name: S::TestConst2
; OBJ-NEXT: }
; ModuleID = 'a.cpp'
source_filename = "a.cpp"
@ -98,43 +99,43 @@ attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-
!llvm.module.flags = !{!26, !27, !28, !29}
!llvm.ident = !{!30}
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 202f144bffd0be254a829924195e1b8ebabcbb79)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !15, globals: !16, nameTableKind: None)
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git 34cd06a9b3bddaa7a989c606bbf1327ee651711c)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !17, globals: !18, nameTableKind: None)
!1 = !DIFile(filename: "a.cpp", directory: "F:\\llvm-project\\__test", checksumkind: CSK_MD5, checksum: "a1dbf3aabea9e8f9d1be48f60287942f")
!2 = !{!3, !11}
!3 = !DICompositeType(tag: DW_TAG_enumeration_type, scope: !4, file: !1, line: 6, baseType: !8, size: 32, elements: !9, identifier: ".?AW4<unnamed-enum-SEnum>@S@@")
!2 = !{!3, !13}
!3 = !DICompositeType(tag: DW_TAG_enumeration_type, scope: !4, file: !1, line: 8, baseType: !8, size: 32, elements: !11, identifier: ".?AW4<unnamed-enum-SEnum>@S@@")
!4 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !1, line: 4, size: 8, flags: DIFlagTypePassByValue, elements: !5, identifier: ".?AUS@@")
!5 = !{!6, !3}
!5 = !{!6, !9, !10, !3}
!6 = !DIDerivedType(tag: DW_TAG_member, name: "TestConst2", scope: !4, file: !1, line: 5, baseType: !7, flags: DIFlagStaticMember, extraData: i32 -10)
!7 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !8)
!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!9 = !{!10}
!10 = !DIEnumerator(name: "SEnum", value: 42)
!11 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "TestEnum", file: !1, line: 8, baseType: !8, size: 32, elements: !12, identifier: ".?AW4TestEnum@@")
!12 = !{!13, !14}
!13 = !DIEnumerator(name: "ENUM_A", value: 2147000000)
!14 = !DIEnumerator(name: "ENUM_B", value: -2147000000)
!15 = !{!4}
!16 = !{!17, !22, !24}
!17 = !DIGlobalVariableExpression(var: !18, expr: !DIExpression(DW_OP_constu, 1078523331, DW_OP_stack_value))
!18 = distinct !DIGlobalVariable(name: "TestConst1", scope: !19, file: !1, line: 2, type: !20, isLocal: true, isDefinition: true)
!19 = !DINamespace(name: "Test1", scope: null)
!20 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !21)
!21 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
!22 = !DIGlobalVariableExpression(var: !23, expr: !DIExpression(DW_OP_constu, 18446744073709551606, DW_OP_stack_value))
!23 = distinct !DIGlobalVariable(name: "TestConst2", scope: !0, file: !1, line: 5, type: !7, isLocal: true, isDefinition: true, declaration: !6)
!9 = !DIDerivedType(tag: DW_TAG_member, name: "TestConst3", scope: !4, file: !1, line: 6, baseType: !7, flags: DIFlagStaticMember, extraData: i32 3)
!10 = !DIDerivedType(tag: DW_TAG_member, name: "TestConst4", scope: !4, file: !1, line: 7, baseType: !7, flags: DIFlagStaticMember, extraData: i32 4)
!11 = !{!12}
!12 = !DIEnumerator(name: "SEnum", value: 42)
!13 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "TestEnum", file: !1, line: 10, baseType: !8, size: 32, elements: !14, identifier: ".?AW4TestEnum@@")
!14 = !{!15, !16}
!15 = !DIEnumerator(name: "ENUM_A", value: 2147000000)
!16 = !DIEnumerator(name: "ENUM_B", value: -2147000000)
!17 = !{!4}
!18 = !{!19, !24}
!19 = !DIGlobalVariableExpression(var: !20, expr: !DIExpression(DW_OP_constu, 1078523331, DW_OP_stack_value))
!20 = distinct !DIGlobalVariable(name: "TestConst1", scope: !21, file: !1, line: 2, type: !22, isLocal: true, isDefinition: true)
!21 = !DINamespace(name: "Test1", scope: null)
!22 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !23)
!23 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
!24 = !DIGlobalVariableExpression(var: !25, expr: !DIExpression(DW_OP_constu, 18446744071562551616, DW_OP_stack_value))
!25 = distinct !DIGlobalVariable(name: "ENUM_B", scope: !0, file: !1, line: 10, type: !11, isLocal: true, isDefinition: true)
!25 = distinct !DIGlobalVariable(name: "ENUM_B", scope: !0, file: !1, line: 12, type: !13, isLocal: true, isDefinition: true)
!26 = !{i32 2, !"CodeView", i32 1}
!27 = !{i32 2, !"Debug Info Version", i32 3}
!28 = !{i32 1, !"wchar_size", i32 2}
!29 = !{i32 7, !"PIC Level", i32 2}
!30 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 202f144bffd0be254a829924195e1b8ebabcbb79)"}
!31 = distinct !DISubprogram(name: "foo", linkageName: "?foo@@YAXXZ", scope: !1, file: !1, line: 13, type: !32, scopeLine: 13, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !34)
!30 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git 34cd06a9b3bddaa7a989c606bbf1327ee651711c)"}
!31 = distinct !DISubprogram(name: "foo", linkageName: "?foo@@YAXXZ", scope: !1, file: !1, line: 15, type: !32, scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !34)
!32 = !DISubroutineType(types: !33)
!33 = !{null}
!34 = !{}
!35 = !DILocation(line: 14, scope: !31)
!36 = !DILocation(line: 15, scope: !31)
!37 = !DILocation(line: 16, scope: !31)
!38 = !DILocation(line: 17, scope: !31)
!39 = !DILocation(line: 18, scope: !31)
!35 = !DILocation(line: 16, scope: !31)
!36 = !DILocation(line: 17, scope: !31)
!37 = !DILocation(line: 18, scope: !31)
!38 = !DILocation(line: 19, scope: !31)
!39 = !DILocation(line: 20, scope: !31)

View File

@ -12,14 +12,22 @@
; Foo f; // FIXME: only needed to force emit 'Foo'
; CHECK: CodeViewTypes [
; CHECK: Array ([[ARRAY_COMPLETE:0x.*]]) {
; CHECK-NEXT: TypeLeafKind: LF_ARRAY (0x1503)
; CHECK-NEXT: ElementType: const char ({{.*}})
; CHECK-NEXT: IndexType: unsigned __int64 (0x23)
; CHECK-NEXT: SizeOf: 5
; CHECK-NEXT: Name:
; CHECK-NEXT: }
; CHECK: ]
; CHECK: Array ([[ARRAY_FWD:0x.*]]) {
; CHECK-NEXT: TypeLeafKind: LF_ARRAY (0x1503)
; CHECK-NEXT: ElementType: const char ({{.*}})
; CHECK-NEXT: IndexType: unsigned __int64 (0x23)
; CHECK-NEXT: SizeOf: 0
; CHECK-NEXT: Name:
; CHECK-NEXT: Name:
; CHECK-NEXT: }
; CHECK: FieldList (0x1003) {
; CHECK: FieldList (0x1004) {
; CHECK-NEXT: TypeLeafKind: LF_FIELDLIST (0x1203)
; CHECK-NEXT: StaticDataMember {
; CHECK-NEXT: TypeLeafKind: LF_STMEMBER (0x150E)
@ -28,14 +36,6 @@
; CHECK-NEXT: Name: str
; CHECK-NEXT: }
; CHECK-NEXT: }
; CHECK: Array ([[ARRAY_COMPLETE:0x.*]]) {
; CHECK-NEXT: TypeLeafKind: LF_ARRAY (0x1503)
; CHECK-NEXT: ElementType: const char ({{.*}})
; CHECK-NEXT: IndexType: unsigned __int64 (0x23)
; CHECK-NEXT: SizeOf: 5
; CHECK-NEXT: Name:
; CHECK-NEXT: }
; CHECK: ]
; CHECK: GlobalData {
; CHECK-NEXT: Kind: S_GDATA32 (0x110D)