[llvm] r326260 - [CodeView] Lower __restrict and other pointer qualifiers correctly

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 27 14:08:15 PST 2018


Author: rnk
Date: Tue Feb 27 14:08:15 2018
New Revision: 326260

URL: http://llvm.org/viewvc/llvm-project?rev=326260&view=rev
Log:
[CodeView] Lower __restrict and other pointer qualifiers correctly

Qualifiers on a pointer or reference type may apply to either the
pointee or the pointer itself. Consider 'const char *' and 'char *
const'. In the first example, the pointee data may not be modified
without casts, and in the second example, the pointer may not be updated
to point to new data.

In the general case, qualifiers are applied to types with LF_MODIFIER
records, which support the usual const and volatile qualifiers as well
as the __unaligned extension qualifier.

However, LF_POINTER records, which are used for pointers, references,
and member pointers, have flags for qualifiers applying to the
*pointer*. In fact, this is the only way to represent the restrict
qualifier, which can only apply to pointers, and cannot qualify regular
data types.

This patch causes LLVM to correctly fold 'const' and 'volatile' pointer
qualifiers into the pointer record, as well as adding support for
'__restrict' qualifiers in the same place.

Based on a patch from Aaron Smith

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

Added:
    llvm/trunk/test/DebugInfo/COFF/type-quals.ll
Modified:
    llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h
    llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
    llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h
    llvm/trunk/lib/DebugInfo/CodeView/RecordName.cpp
    llvm/trunk/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h?rev=326260&r1=326259&r2=326260&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h Tue Feb 27 14:08:15 2018
@@ -330,6 +330,10 @@ public:
     return !!(Attrs & uint32_t(PointerOptions::Unaligned));
   }
 
+  bool isRestrict() const {
+    return !!(Attrs & uint32_t(PointerOptions::Restrict));
+  }
+
   TypeIndex ReferentType;
   uint32_t Attrs;
   Optional<MemberPointerInfo> MemberInfo;

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp?rev=326260&r1=326259&r2=326260&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp Tue Feb 27 14:08:15 2018
@@ -1268,6 +1268,7 @@ TypeIndex CodeViewDebug::lowerType(const
     return lowerTypePointer(cast<DIDerivedType>(Ty));
   case dwarf::DW_TAG_ptr_to_member_type:
     return lowerTypeMemberPointer(cast<DIDerivedType>(Ty));
+  case dwarf::DW_TAG_restrict_type:
   case dwarf::DW_TAG_const_type:
   case dwarf::DW_TAG_volatile_type:
   // TODO: add support for DW_TAG_atomic_type here
@@ -1452,12 +1453,13 @@ TypeIndex CodeViewDebug::lowerTypeBasic(
   return TypeIndex(STK);
 }
 
-TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty) {
+TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty,
+                                          PointerOptions PO) {
   TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType());
 
-  // Pointers to simple types can use SimpleTypeMode, rather than having a
-  // dedicated pointer type record.
-  if (PointeeTI.isSimple() &&
+  // Pointers to simple types without any options can use SimpleTypeMode, rather
+  // than having a dedicated pointer type record.
+  if (PointeeTI.isSimple() && PO == PointerOptions::None &&
       PointeeTI.getSimpleMode() == SimpleTypeMode::Direct &&
       Ty->getTag() == dwarf::DW_TAG_pointer_type) {
     SimpleTypeMode Mode = Ty->getSizeInBits() == 64
@@ -1481,10 +1483,7 @@ TypeIndex CodeViewDebug::lowerTypePointe
     PM = PointerMode::RValueReference;
     break;
   }
-  // FIXME: MSVC folds qualifiers into PointerOptions in the context of a method
-  // 'this' pointer, but not normal contexts. Figure out what we're supposed to
-  // do.
-  PointerOptions PO = PointerOptions::None;
+
   PointerRecord PR(PointeeTI, PK, PM, PO, Ty->getSizeInBits() / 8);
   return TypeTable.writeLeafType(PR);
 }
@@ -1522,7 +1521,8 @@ translatePtrToMemberRep(unsigned SizeInB
   llvm_unreachable("invalid ptr to member representation");
 }
 
-TypeIndex CodeViewDebug::lowerTypeMemberPointer(const DIDerivedType *Ty) {
+TypeIndex CodeViewDebug::lowerTypeMemberPointer(const DIDerivedType *Ty,
+                                                PointerOptions PO) {
   assert(Ty->getTag() == dwarf::DW_TAG_ptr_to_member_type);
   TypeIndex ClassTI = getTypeIndex(Ty->getClassType());
   TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType(), Ty->getClassType());
@@ -1531,7 +1531,7 @@ TypeIndex CodeViewDebug::lowerTypeMember
   bool IsPMF = isa<DISubroutineType>(Ty->getBaseType());
   PointerMode PM = IsPMF ? PointerMode::PointerToMemberFunction
                          : PointerMode::PointerToDataMember;
-  PointerOptions PO = PointerOptions::None; // FIXME
+
   assert(Ty->getSizeInBits() / 8 <= 0xff && "pointer size too big");
   uint8_t SizeInBytes = Ty->getSizeInBits() / 8;
   MemberPointerInfo MPI(
@@ -1556,6 +1556,7 @@ static CallingConvention dwarfCCToCodeVi
 
 TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) {
   ModifierOptions Mods = ModifierOptions::None;
+  PointerOptions PO = PointerOptions::None;
   bool IsModifier = true;
   const DIType *BaseTy = Ty;
   while (IsModifier && BaseTy) {
@@ -1563,9 +1564,16 @@ TypeIndex CodeViewDebug::lowerTypeModifi
     switch (BaseTy->getTag()) {
     case dwarf::DW_TAG_const_type:
       Mods |= ModifierOptions::Const;
+      PO |= PointerOptions::Const;
       break;
     case dwarf::DW_TAG_volatile_type:
       Mods |= ModifierOptions::Volatile;
+      PO |= PointerOptions::Volatile;
+      break;
+    case dwarf::DW_TAG_restrict_type:
+      // Only pointer types be marked with __restrict. There is no known flag
+      // for __restrict in LF_MODIFIER records.
+      PO |= PointerOptions::Restrict;
       break;
     default:
       IsModifier = false;
@@ -1574,7 +1582,31 @@ TypeIndex CodeViewDebug::lowerTypeModifi
     if (IsModifier)
       BaseTy = cast<DIDerivedType>(BaseTy)->getBaseType().resolve();
   }
+
+  // Check if the inner type will use an LF_POINTER record. If so, the
+  // qualifiers will go in the LF_POINTER record. This comes up for types like
+  // 'int *const' and 'int *__restrict', not the more common cases like 'const
+  // char *'.
+  if (BaseTy) {
+    switch (BaseTy->getTag()) {
+    case dwarf::DW_TAG_pointer_type:
+    case dwarf::DW_TAG_reference_type:
+    case dwarf::DW_TAG_rvalue_reference_type:
+      return lowerTypePointer(cast<DIDerivedType>(BaseTy), PO);
+    case dwarf::DW_TAG_ptr_to_member_type:
+      return lowerTypeMemberPointer(cast<DIDerivedType>(BaseTy), PO);
+    default:
+      break;
+    }
+  }
+
   TypeIndex ModifiedTI = getTypeIndex(BaseTy);
+
+  // Return the base type index if there aren't any modifiers. For example, the
+  // metadata could contain restrict wrappers around non-pointer types.
+  if (Mods == ModifierOptions::None)
+    return ModifiedTI;
+
   ModifierRecord MR(ModifiedTI, Mods);
   return TypeTable.writeLeafType(MR);
 }

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h?rev=326260&r1=326259&r2=326260&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h Tue Feb 27 14:08:15 2018
@@ -283,8 +283,12 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDe
   codeview::TypeIndex lowerTypeAlias(const DIDerivedType *Ty);
   codeview::TypeIndex lowerTypeArray(const DICompositeType *Ty);
   codeview::TypeIndex lowerTypeBasic(const DIBasicType *Ty);
-  codeview::TypeIndex lowerTypePointer(const DIDerivedType *Ty);
-  codeview::TypeIndex lowerTypeMemberPointer(const DIDerivedType *Ty);
+  codeview::TypeIndex lowerTypePointer(
+      const DIDerivedType *Ty,
+      codeview::PointerOptions PO = codeview::PointerOptions::None);
+  codeview::TypeIndex lowerTypeMemberPointer(
+      const DIDerivedType *Ty,
+      codeview::PointerOptions PO = codeview::PointerOptions::None);
   codeview::TypeIndex lowerTypeModifier(const DIDerivedType *Ty);
   codeview::TypeIndex lowerTypeFunction(const DISubroutineType *Ty);
   codeview::TypeIndex lowerTypeVFTableShape(const DIDerivedType *Ty);

Modified: llvm/trunk/lib/DebugInfo/CodeView/RecordName.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/RecordName.cpp?rev=326260&r1=326259&r2=326260&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/RecordName.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/RecordName.cpp Tue Feb 27 14:08:15 2018
@@ -167,13 +167,6 @@ Error TypeNameComputer::visitKnownRecord
     StringRef Class = Types.getTypeName(MI.getContainingType());
     Name = formatv("{0} {1}::*", Pointee, Class);
   } else {
-    if (Ptr.isConst())
-      Name.append("const ");
-    if (Ptr.isVolatile())
-      Name.append("volatile ");
-    if (Ptr.isUnaligned())
-      Name.append("__unaligned ");
-
     Name.append(Types.getTypeName(Ptr.getReferentType()));
 
     if (Ptr.getMode() == PointerMode::LValueReference)
@@ -182,6 +175,17 @@ Error TypeNameComputer::visitKnownRecord
       Name.append("&&");
     else if (Ptr.getMode() == PointerMode::Pointer)
       Name.append("*");
+
+    // Qualifiers in pointer records apply to the pointer, not the pointee, so
+    // they go on the right.
+    if (Ptr.isConst())
+      Name.append(" const");
+    if (Ptr.isVolatile())
+      Name.append(" volatile");
+    if (Ptr.isUnaligned())
+      Name.append(" __unaligned");
+    if (Ptr.isRestrict())
+      Name.append(" __restrict");
   }
   return Error::success();
 }

Modified: llvm/trunk/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp?rev=326260&r1=326259&r2=326260&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp Tue Feb 27 14:08:15 2018
@@ -370,6 +370,7 @@ Error TypeDumpVisitor::visitKnownRecord(
   W->printNumber("IsConst", Ptr.isConst());
   W->printNumber("IsVolatile", Ptr.isVolatile());
   W->printNumber("IsUnaligned", Ptr.isUnaligned());
+  W->printNumber("IsRestrict", Ptr.isRestrict());
   W->printNumber("SizeOf", Ptr.getSize());
 
   if (Ptr.isPointerToMember()) {

Added: llvm/trunk/test/DebugInfo/COFF/type-quals.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/type-quals.ll?rev=326260&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/type-quals.ll (added)
+++ llvm/trunk/test/DebugInfo/COFF/type-quals.ll Tue Feb 27 14:08:15 2018
@@ -0,0 +1,573 @@
+; RUN: llc < %s -filetype=obj | llvm-readobj - -codeview | FileCheck %s
+
+; C++ source to regenerate:
+; $ cat m.cpp
+; union Union {
+;   int * __restrict x_member;
+;   float * __restrict y_member;
+;   int* volatile __restrict m_volatile;
+; };
+;
+; int f(const volatile int* __restrict arg_crv) {
+;   Union u;
+;   const int *p;
+;   const volatile int v = 0;
+;   return 1;
+; }
+;
+; void g(int& __restrict arg_ref) {
+;   const int x = 10;
+;   const char str[] = "abc";
+; }
+;
+; void h() {
+;   struct Foo {
+;     int a;
+;     int func(int x) __restrict { return 1; }
+;   };
+;
+;   Foo s = { 10 };
+;
+;   int* __restrict p_object = &s.a;
+;
+;   int Foo:: * __restrict p_data_member = &Foo::a;
+;
+;   int (Foo::* p_member_func)(int) __restrict = &Foo::func;
+; }
+;
+; $ clang++ m.cpp -S -emit-llvm -g -gcodeview -o m.ll
+
+
+; CHECK: CodeViewTypes [
+; CHECK:   Section: .debug$T (7)
+; CHECK:   Magic: 0x4
+; CHECK:   Modifier (0x1000) {
+; CHECK:     TypeLeafKind: LF_MODIFIER (0x1001)
+; CHECK:     ModifiedType: int (0x74)
+; CHECK:     Modifiers [ (0x3)
+; CHECK:       Const (0x1)
+; CHECK:       Volatile (0x2)
+; CHECK:     ]
+; CHECK:   }
+; CHECK:   Pointer (0x1001) {
+; CHECK:     TypeLeafKind: LF_POINTER (0x1002)
+; CHECK:     PointeeType: const volatile int (0x1000)
+; CHECK:     PointerAttributes: 0x1100C
+; CHECK:     PtrType: Near64 (0xC)
+; CHECK:     PtrMode: Pointer (0x0)
+; CHECK:     IsFlat: 0
+; CHECK:     IsConst: 0
+; CHECK:     IsVolatile: 0
+; CHECK:     IsUnaligned: 0
+; CHECK:     IsRestrict: 1
+; CHECK:     SizeOf: 8
+; CHECK:   }
+; CHECK:   ArgList (0x1002) {
+; CHECK:     TypeLeafKind: LF_ARGLIST (0x1201)
+; CHECK:     NumArgs: 1
+; CHECK:     Arguments [
+; CHECK:       ArgType: const volatile int* __restrict (0x1001)
+; CHECK:     ]
+; CHECK:   }
+; CHECK:   Procedure (0x1003) {
+; CHECK:     TypeLeafKind: LF_PROCEDURE (0x1008)
+; CHECK:     ReturnType: int (0x74)
+; CHECK:     CallingConvention: NearC (0x0)
+; CHECK:     FunctionOptions [ (0x0)
+; CHECK:     ]
+; CHECK:     NumParameters: 1
+; CHECK:     ArgListType: (const volatile int* __restrict) (0x1002)
+; CHECK:   }
+; CHECK:   FuncId (0x1004) {
+; CHECK:     TypeLeafKind: LF_FUNC_ID (0x1601)
+; CHECK:     ParentScope: 0x0
+; CHECK:     FunctionType: int (const volatile int* __restrict) (0x1003)
+; CHECK:     Name: f
+; CHECK:   }
+; CHECK:   Union (0x1005) {
+; CHECK:     TypeLeafKind: LF_UNION (0x1506)
+; CHECK:     MemberCount: 0
+; CHECK:     Properties [ (0x280)
+; CHECK:       ForwardReference (0x80)
+; CHECK:       HasUniqueName (0x200)
+; CHECK:     ]
+; CHECK:     FieldList: 0x0
+; CHECK:     SizeOf: 0
+; CHECK:     Name: Union
+; CHECK:     LinkageName: .?ATUnion@@
+; CHECK:   }
+; CHECK:   Pointer (0x1006) {
+; CHECK:     TypeLeafKind: LF_POINTER (0x1002)
+; CHECK:     PointeeType: int (0x74)
+; CHECK:     PointerAttributes: 0x1100C
+; CHECK:     PtrType: Near64 (0xC)
+; CHECK:     PtrMode: Pointer (0x0)
+; CHECK:     IsFlat: 0
+; CHECK:     IsConst: 0
+; CHECK:     IsVolatile: 0
+; CHECK:     IsUnaligned: 0
+; CHECK:     IsRestrict: 1
+; CHECK:     SizeOf: 8
+; CHECK:   }
+; CHECK:   Pointer (0x1007) {
+; CHECK:     TypeLeafKind: LF_POINTER (0x1002)
+; CHECK:     PointeeType: float (0x40)
+; CHECK:     PointerAttributes: 0x1100C
+; CHECK:     PtrType: Near64 (0xC)
+; CHECK:     PtrMode: Pointer (0x0)
+; CHECK:     IsFlat: 0
+; CHECK:     IsConst: 0
+; CHECK:     IsVolatile: 0
+; CHECK:     IsUnaligned: 0
+; CHECK:     IsRestrict: 1
+; CHECK:     SizeOf: 8
+; CHECK:   }
+; CHECK:   Pointer (0x1008) {
+; CHECK:     TypeLeafKind: LF_POINTER (0x1002)
+; CHECK:     PointeeType: int (0x74)
+; CHECK:     PointerAttributes: 0x1120C
+; CHECK:     PtrType: Near64 (0xC)
+; CHECK:     PtrMode: Pointer (0x0)
+; CHECK:     IsFlat: 0
+; CHECK:     IsConst: 0
+; CHECK:     IsVolatile: 1
+; CHECK:     IsUnaligned: 0
+; CHECK:     IsRestrict: 1
+; CHECK:     SizeOf: 8
+; CHECK:   }
+; CHECK:   FieldList (0x1009) {
+; CHECK:     TypeLeafKind: LF_FIELDLIST (0x1203)
+; CHECK:     DataMember {
+; CHECK:       TypeLeafKind: LF_MEMBER (0x150D)
+; CHECK:       AccessSpecifier: Public (0x3)
+; CHECK:       Type: int* __restrict (0x1006)
+; CHECK:       FieldOffset: 0x0
+; CHECK:       Name: x_member
+; CHECK:     }
+; CHECK:     DataMember {
+; CHECK:       TypeLeafKind: LF_MEMBER (0x150D)
+; CHECK:       AccessSpecifier: Public (0x3)
+; CHECK:       Type: float* __restrict (0x1007)
+; CHECK:       FieldOffset: 0x0
+; CHECK:       Name: y_member
+; CHECK:     }
+; CHECK:     DataMember {
+; CHECK:       TypeLeafKind: LF_MEMBER (0x150D)
+; CHECK:       AccessSpecifier: Public (0x3)
+; CHECK:       Type: int* volatile __restrict (0x1008)
+; CHECK:       FieldOffset: 0x0
+; CHECK:       Name: m_volatile
+; CHECK:     }
+; CHECK:   }
+
+; CHECK:   Modifier (0x100D) {
+; CHECK:     TypeLeafKind: LF_MODIFIER (0x1001)
+; CHECK:     ModifiedType: int (0x74)
+; CHECK:     Modifiers [ (0x1)
+; CHECK:       Const (0x1)
+; CHECK:     ]
+; CHECK:   }
+; CHECK:   Pointer (0x100E) {
+; CHECK:     TypeLeafKind: LF_POINTER (0x1002)
+; CHECK:     PointeeType: const int (0x100D)
+; CHECK:     PointerAttributes: 0x1000C
+; CHECK:     PtrType: Near64 (0xC)
+; CHECK:     PtrMode: Pointer (0x0)
+; CHECK:     IsFlat: 0
+; CHECK:     IsConst: 0
+; CHECK:     IsVolatile: 0
+; CHECK:     IsUnaligned: 0
+; CHECK:     IsRestrict: 0
+; CHECK:     SizeOf: 8
+; CHECK:   }
+; CHECK:   Pointer (0x100F) {
+; CHECK:     TypeLeafKind: LF_POINTER (0x1002)
+; CHECK:     PointeeType: int (0x74)
+; CHECK:     PointerAttributes: 0x1102C
+; CHECK:     PtrType: Near64 (0xC)
+; CHECK:     PtrMode: LValueReference (0x1)
+; CHECK:     IsFlat: 0
+; CHECK:     IsConst: 0
+; CHECK:     IsVolatile: 0
+; CHECK:     IsUnaligned: 0
+; CHECK:     IsRestrict: 1
+; CHECK:     SizeOf: 8
+; CHECK:   }
+; CHECK:   ArgList (0x1010) {
+; CHECK:     TypeLeafKind: LF_ARGLIST (0x1201)
+; CHECK:     NumArgs: 1
+; CHECK:     Arguments [
+; CHECK:       ArgType: int& __restrict (0x100F)
+; CHECK:     ]
+; CHECK:   }
+; CHECK:   Procedure (0x1011) {
+; CHECK:     TypeLeafKind: LF_PROCEDURE (0x1008)
+; CHECK:     ReturnType: void (0x3)
+; CHECK:     CallingConvention: NearC (0x0)
+; CHECK:     FunctionOptions [ (0x0)
+; CHECK:     ]
+; CHECK:     NumParameters: 1
+; CHECK:     ArgListType: (int& __restrict) (0x1010)
+; CHECK:   }
+; CHECK:   FuncId (0x1012) {
+; CHECK:     TypeLeafKind: LF_FUNC_ID (0x1601)
+; CHECK:     ParentScope: 0x0
+; CHECK:     FunctionType: void (int& __restrict) (0x1011)
+; CHECK:     Name: g
+; CHECK:   }
+; CHECK:   ArgList (0x1013) {
+; CHECK:     TypeLeafKind: LF_ARGLIST (0x1201)
+; CHECK:     NumArgs: 0
+; CHECK:     Arguments [
+; CHECK:     ]
+; CHECK:   }
+; CHECK:   Procedure (0x1014) {
+; CHECK:     TypeLeafKind: LF_PROCEDURE (0x1008)
+; CHECK:     ReturnType: void (0x3)
+; CHECK:     CallingConvention: NearC (0x0)
+; CHECK:     FunctionOptions [ (0x0)
+; CHECK:     ]
+; CHECK:     NumParameters: 0
+; CHECK:     ArgListType: () (0x1013)
+; CHECK:   }
+; CHECK:   FuncId (0x1015) {
+; CHECK:     TypeLeafKind: LF_FUNC_ID (0x1601)
+; CHECK:     ParentScope: 0x0
+; CHECK:     FunctionType: void () (0x1014)
+; CHECK:     Name: h
+; CHECK:   }
+; CHECK:   Struct (0x1016) {
+; CHECK:     TypeLeafKind: LF_STRUCTURE (0x1505)
+; CHECK:     MemberCount: 0
+; CHECK:     Properties [ (0x180)
+; CHECK:       ForwardReference (0x80)
+; CHECK:       Scoped (0x100)
+; CHECK:     ]
+; CHECK:     FieldList: 0x0
+; CHECK:     DerivedFrom: 0x0
+; CHECK:     VShape: 0x0
+; CHECK:     SizeOf: 0
+; CHECK:     Name: h::Foo
+; CHECK:   }
+; CHECK:   Pointer (0x1017) {
+; CHECK:     TypeLeafKind: LF_POINTER (0x1002)
+; CHECK:     PointeeType: h::Foo (0x1016)
+; CHECK:     PointerAttributes: 0x1000C
+; CHECK:     PtrType: Near64 (0xC)
+; CHECK:     PtrMode: Pointer (0x0)
+; CHECK:     IsFlat: 0
+; CHECK:     IsConst: 0
+; CHECK:     IsVolatile: 0
+; CHECK:     IsUnaligned: 0
+; CHECK:     IsRestrict: 0
+; CHECK:     SizeOf: 8
+; CHECK:   }
+; CHECK:   ArgList (0x1018) {
+; CHECK:     TypeLeafKind: LF_ARGLIST (0x1201)
+; CHECK:     NumArgs: 1
+; CHECK:     Arguments [
+; CHECK:       ArgType: int (0x74)
+; CHECK:     ]
+; CHECK:   }
+; CHECK:   MemberFunction (0x1019) {
+; CHECK:     TypeLeafKind: LF_MFUNCTION (0x1009)
+; CHECK:     ReturnType: int (0x74)
+; CHECK:     ClassType: h::Foo (0x1016)
+; CHECK:     ThisType: h::Foo* (0x1017)
+; CHECK:     CallingConvention: NearC (0x0)
+; CHECK:     FunctionOptions [ (0x0)
+; CHECK:     ]
+; CHECK:     NumParameters: 1
+; CHECK:     ArgListType: (int) (0x1018)
+; CHECK:     ThisAdjustment: 0
+; CHECK:   }
+; CHECK:   FieldList (0x101A) {
+; CHECK:     TypeLeafKind: LF_FIELDLIST (0x1203)
+; CHECK:     DataMember {
+; CHECK:       TypeLeafKind: LF_MEMBER (0x150D)
+; CHECK:       AccessSpecifier: Public (0x3)
+; CHECK:       Type: int (0x74)
+; CHECK:       FieldOffset: 0x0
+; CHECK:       Name: a
+; CHECK:     }
+; CHECK:     OneMethod {
+; CHECK:       TypeLeafKind: LF_ONEMETHOD (0x1511)
+; CHECK:       AccessSpecifier: Public (0x3)
+; CHECK:       Type: int h::Foo::(int) (0x1019)
+; CHECK:       Name: func
+; CHECK:     }
+; CHECK:   }
+; CHECK:   Struct (0x101B) {
+; CHECK:     TypeLeafKind: LF_STRUCTURE (0x1505)
+; CHECK:     MemberCount: 2
+; CHECK:     Properties [ (0x100)
+; CHECK:       Scoped (0x100)
+; CHECK:     ]
+; CHECK:     FieldList: <field list> (0x101A)
+; CHECK:     DerivedFrom: 0x0
+; CHECK:     VShape: 0x0
+; CHECK:     SizeOf: 4
+; CHECK:     Name: h::Foo
+; CHECK:   }
+
+; CHECK:   Pointer (0x101D) {
+; CHECK:     TypeLeafKind: LF_POINTER (0x1002)
+; CHECK:     PointeeType: int (0x74)
+; CHECK:     PointerAttributes: 0x904C
+; CHECK:     PtrType: Near64 (0xC)
+; CHECK:     PtrMode: PointerToDataMember (0x2)
+; CHECK:     IsFlat: 0
+; CHECK:     IsConst: 0
+; CHECK:     IsVolatile: 0
+; CHECK:     IsUnaligned: 0
+; CHECK:     IsRestrict: 1
+; CHECK:     SizeOf: 4
+; CHECK:     ClassType: h::Foo (0x1016)
+; CHECK:     Representation: SingleInheritanceData (0x1)
+; CHECK:   }
+; CHECK:   Pointer (0x101E) {
+; CHECK:     TypeLeafKind: LF_POINTER (0x1002)
+; CHECK:     PointeeType: int h::Foo::(int) (0x1019)
+; CHECK:     PointerAttributes: 0x1006C
+; CHECK:     PtrType: Near64 (0xC)
+; CHECK:     PtrMode: PointerToMemberFunction (0x3)
+; CHECK:     IsFlat: 0
+; CHECK:     IsConst: 0
+; CHECK:     IsVolatile: 0
+; CHECK:     IsUnaligned: 0
+; CHECK:     IsRestrict: 0
+; CHECK:     SizeOf: 8
+; CHECK:     ClassType: h::Foo (0x1016)
+; CHECK:     Representation: SingleInheritanceFunction (0x5)
+; CHECK:   }
+; CHECK:   MemberFuncId (0x101F) {
+; CHECK:     TypeLeafKind: LF_MFUNC_ID (0x1602)
+; CHECK:     ClassType: h::Foo (0x1016)
+; CHECK:     FunctionType: int h::Foo::(int) (0x1019)
+; CHECK:     Name: func
+; CHECK:   }
+; CHECK:   Modifier (0x1020) {
+; CHECK:     TypeLeafKind: LF_MODIFIER (0x1001)
+; CHECK:     ModifiedType: char (0x70)
+; CHECK:     Modifiers [ (0x1)
+; CHECK:       Const (0x1)
+; CHECK:     ]
+; CHECK:   }
+; CHECK:   Array (0x1021) {
+; CHECK:     TypeLeafKind: LF_ARRAY (0x1503)
+; CHECK:     ElementType: const char (0x1020)
+; CHECK:     IndexType: unsigned __int64 (0x23)
+; CHECK:     SizeOf: 4
+; CHECK:     Name:
+; CHECK:   }
+; CHECK: ]
+
+; CHECK-LABEL: CodeViewDebugInfo [
+; CHECK-NEXT:   Section: .debug$S (6)
+; CHECK:   Subsection [
+; CHECK:     SubSectionType: Symbols (0xF1)
+; CHECK:     GlobalProcIdSym {
+; CHECK:       Kind: S_GPROC32_ID (0x1147)
+; CHECK:       FunctionType: f ({{.*}})
+; CHECK:       CodeOffset: ?f@@YAHPEIDH at Z+0x0
+; CHECK:       DisplayName: f
+; CHECK:       LinkageName: ?f@@YAHPEIDH at Z
+; CHECK:     }
+; CHECK:     LocalSym {
+; CHECK:       Kind: S_LOCAL (0x113E)
+; CHECK:       Type: const volatile int* __restrict (0x1001)
+; CHECK:       VarName: arg_crv
+; CHECK:     }
+; CHECK:     LocalSym {
+; CHECK:       Kind: S_LOCAL (0x113E)
+; CHECK:       Type: Union (0x100A)
+; CHECK:       VarName: u
+; CHECK:     }
+; CHECK:     LocalSym {
+; CHECK:       Kind: S_LOCAL (0x113E)
+; CHECK:       Type: const int* (0x100E)
+; CHECK:       VarName: p
+; CHECK:     }
+; CHECK:     LocalSym {
+; CHECK:       Kind: S_LOCAL (0x113E)
+; CHECK:       Type: const volatile int (0x1000)
+; CHECK:       VarName: v
+; CHECK:     }
+
+; ModuleID = 'm.cpp'
+source_filename = "m.cpp"
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.11.25507"
+
+%struct.Foo = type { i32 }
+%union.Union = type { i32* }
+
+@"\01?str@?1??g@@YAXAEIAH at Z@3QBDB" = internal constant [4 x i8] c"abc\00", align 1, !dbg !0
+@"\01?s@?1??h@@YAXXZ at 3UFoo@?1??1 at YAXXZ@A" = private unnamed_addr constant %struct.Foo { i32 10 }, align 4
+
+; Function Attrs: noinline nounwind optnone uwtable
+define i32 @"\01?f@@YAHPEIDH at Z"(i32* noalias %arg_crv) #0 !dbg !22 {
+entry:
+  %arg_crv.addr = alloca i32*, align 8
+  %u = alloca %union.Union, align 8
+  %p = alloca i32*, align 8
+  %v = alloca i32, align 4
+  store i32* %arg_crv, i32** %arg_crv.addr, align 8
+  call void @llvm.dbg.declare(metadata i32** %arg_crv.addr, metadata !29, metadata !DIExpression()), !dbg !30
+  call void @llvm.dbg.declare(metadata %union.Union* %u, metadata !31, metadata !DIExpression()), !dbg !43
+  call void @llvm.dbg.declare(metadata i32** %p, metadata !44, metadata !DIExpression()), !dbg !47
+  call void @llvm.dbg.declare(metadata i32* %v, metadata !48, metadata !DIExpression()), !dbg !49
+  store volatile i32 0, i32* %v, align 4, !dbg !49
+  ret i32 1, !dbg !50
+}
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: noinline nounwind optnone uwtable
+define void @"\01?g@@YAXAEIAH at Z"(i32* noalias dereferenceable(4) %arg_ref) #0 !dbg !2 {
+entry:
+  %arg_ref.addr = alloca i32*, align 8
+  %x = alloca i32, align 4
+  store i32* %arg_ref, i32** %arg_ref.addr, align 8
+  call void @llvm.dbg.declare(metadata i32** %arg_ref.addr, metadata !51, metadata !DIExpression()), !dbg !52
+  call void @llvm.dbg.declare(metadata i32* %x, metadata !53, metadata !DIExpression()), !dbg !54
+  store i32 10, i32* %x, align 4, !dbg !54
+  ret void, !dbg !55
+}
+
+; Function Attrs: noinline nounwind optnone uwtable
+define void @"\01?h@@YAXXZ"() #0 !dbg !56 {
+entry:
+  %s = alloca %struct.Foo, align 4
+  %p_object = alloca i32*, align 8
+  %p_data_member = alloca i32, align 8
+  %p_member_func = alloca i8*, align 8
+  call void @llvm.dbg.declare(metadata %struct.Foo* %s, metadata !59, metadata !DIExpression()), !dbg !68
+  %0 = bitcast %struct.Foo* %s to i8*, !dbg !68
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast (%struct.Foo* @"\01?s@?1??h@@YAXXZ at 3UFoo@?1??1 at YAXXZ@A" to i8*), i64 4, i1 false), !dbg !68
+  call void @llvm.dbg.declare(metadata i32** %p_object, metadata !69, metadata !DIExpression()), !dbg !70
+  %a = getelementptr inbounds %struct.Foo, %struct.Foo* %s, i32 0, i32 0, !dbg !71
+  store i32* %a, i32** %p_object, align 8, !dbg !70
+  call void @llvm.dbg.declare(metadata i32* %p_data_member, metadata !72, metadata !DIExpression()), !dbg !75
+  store i32 0, i32* %p_data_member, align 8, !dbg !75
+  call void @llvm.dbg.declare(metadata i8** %p_member_func, metadata !76, metadata !DIExpression()), !dbg !78
+  store i8* bitcast (i32 (%struct.Foo*, i32)* @"\01?func at Foo@?1??h@@YAXXZ at QEIAAHH@Z" to i8*), i8** %p_member_func, align 8, !dbg !78
+  ret void, !dbg !79
+}
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) #2
+
+; Function Attrs: noinline nounwind optnone uwtable
+define internal i32 @"\01?func at Foo@?1??h@@YAXXZ at QEIAAHH@Z"(%struct.Foo* %this, i32 %x) #0 align 2 !dbg !80 {
+entry:
+  %x.addr = alloca i32, align 4
+  %this.addr = alloca %struct.Foo*, align 8
+  store i32 %x, i32* %x.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %x.addr, metadata !81, metadata !DIExpression()), !dbg !82
+  store %struct.Foo* %this, %struct.Foo** %this.addr, align 8
+  call void @llvm.dbg.declare(metadata %struct.Foo** %this.addr, metadata !83, metadata !DIExpression()), !dbg !85
+  %this1 = load %struct.Foo*, %struct.Foo** %this.addr, align 8
+  ret i32 1, !dbg !86
+}
+
+attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone speculatable }
+attributes #2 = { argmemonly nounwind }
+
+!llvm.dbg.cu = !{!9}
+!llvm.module.flags = !{!17, !18, !19, !20}
+!llvm.ident = !{!21}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "str", scope: !2, file: !3, line: 18, type: !12, isLocal: true, isDefinition: true)
+!2 = distinct !DISubprogram(name: "g", linkageName: "\01?g@@YAXAEIAH at Z", scope: !3, file: !3, line: 16, type: !4, isLocal: false, isDefinition: true, scopeLine: 16, flags: DIFlagPrototyped, isOptimized: false, unit: !9, variables: !10)
+!3 = !DIFile(filename: "m.cpp", directory: "C:\5CUsers\5CHui\5Ctmp\5Chui", checksumkind: CSK_MD5, checksum: "a8da0f4dca948db1ef1129c8728a881c")
+!4 = !DISubroutineType(types: !5)
+!5 = !{null, !6}
+!6 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !7)
+!7 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !8, size: 64)
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 7.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !10, globals: !11)
+!10 = !{}
+!11 = !{!0}
+!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 32, elements: !15)
+!13 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !14)
+!14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!15 = !{!16}
+!16 = !DISubrange(count: 4)
+!17 = !{i32 2, !"CodeView", i32 1}
+!18 = !{i32 2, !"Debug Info Version", i32 3}
+!19 = !{i32 1, !"wchar_size", i32 2}
+!20 = !{i32 7, !"PIC Level", i32 2}
+!21 = !{!"clang version 7.0.0 "}
+!22 = distinct !DISubprogram(name: "f", linkageName: "\01?f@@YAHPEIDH at Z", scope: !3, file: !3, line: 9, type: !23, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false, unit: !9, variables: !10)
+!23 = !DISubroutineType(types: !24)
+!24 = !{!8, !25}
+!25 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !26)
+!26 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !27, size: 64)
+!27 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !28)
+!28 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !8)
+!29 = !DILocalVariable(name: "arg_crv", arg: 1, scope: !22, file: !3, line: 9, type: !25)
+!30 = !DILocation(line: 9, column: 39, scope: !22)
+!31 = !DILocalVariable(name: "u", scope: !22, file: !3, line: 10, type: !32)
+!32 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "Union", file: !3, line: 3, size: 64, flags: DIFlagTypePassByValue, elements: !33, identifier: ".?ATUnion@@")
+!33 = !{!34, !37, !41}
+!34 = !DIDerivedType(tag: DW_TAG_member, name: "x_member", scope: !32, file: !3, line: 4, baseType: !35, size: 64)
+!35 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !36)
+!36 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64)
+!37 = !DIDerivedType(tag: DW_TAG_member, name: "y_member", scope: !32, file: !3, line: 5, baseType: !38, size: 64)
+!38 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !39)
+!39 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !40, size: 64)
+!40 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
+!41 = !DIDerivedType(tag: DW_TAG_member, name: "m_volatile", scope: !32, file: !3, line: 6, baseType: !42, size: 64)
+!42 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !35)
+!43 = !DILocation(line: 10, column: 10, scope: !22)
+!44 = !DILocalVariable(name: "p", scope: !22, file: !3, line: 11, type: !45)
+!45 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !46, size: 64)
+!46 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !8)
+!47 = !DILocation(line: 11, column: 15, scope: !22)
+!48 = !DILocalVariable(name: "v", scope: !22, file: !3, line: 12, type: !27)
+!49 = !DILocation(line: 12, column: 23, scope: !22)
+!50 = !DILocation(line: 13, column: 4, scope: !22)
+!51 = !DILocalVariable(name: "arg_ref", arg: 1, scope: !2, file: !3, line: 16, type: !6)
+!52 = !DILocation(line: 16, column: 25, scope: !2)
+!53 = !DILocalVariable(name: "x", scope: !2, file: !3, line: 17, type: !46)
+!54 = !DILocation(line: 17, column: 14, scope: !2)
+!55 = !DILocation(line: 19, column: 2, scope: !2)
+!56 = distinct !DISubprogram(name: "h", linkageName: "\01?h@@YAXXZ", scope: !3, file: !3, line: 21, type: !57, isLocal: false, isDefinition: true, scopeLine: 21, flags: DIFlagPrototyped, isOptimized: false, unit: !9, variables: !10)
+!57 = !DISubroutineType(types: !58)
+!58 = !{null}
+!59 = !DILocalVariable(name: "s", scope: !56, file: !3, line: 27, type: !60)
+!60 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", scope: !56, file: !3, line: 22, size: 32, flags: DIFlagTypePassByValue, elements: !61)
+!61 = !{!62, !63}
+!62 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !60, file: !3, line: 23, baseType: !8, size: 32)
+!63 = !DISubprogram(name: "func", scope: !60, file: !3, line: 24, type: !64, isLocal: false, isDefinition: false, scopeLine: 24, flags: DIFlagPrototyped, isOptimized: false)
+!64 = !DISubroutineType(types: !65)
+!65 = !{!8, !66, !8}
+
+; FIXME: Clang emits wrong debug info here because of PR17747. We should
+; regenerate this IR when it is fixed.
+!66 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !67, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!67 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !60)
+
+!68 = !DILocation(line: 27, column: 8, scope: !56)
+!69 = !DILocalVariable(name: "p_object", scope: !56, file: !3, line: 29, type: !35)
+!70 = !DILocation(line: 29, column: 20, scope: !56)
+!71 = !DILocation(line: 29, column: 34, scope: !56)
+!72 = !DILocalVariable(name: "p_data_member", scope: !56, file: !3, line: 31, type: !73)
+!73 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !74)
+!74 = !DIDerivedType(tag: DW_TAG_ptr_to_member_type, baseType: !8, size: 32, flags: DIFlagSingleInheritance, extraData: !60)
+!75 = !DILocation(line: 31, column: 27, scope: !56)
+!76 = !DILocalVariable(name: "p_member_func", scope: !56, file: !3, line: 33, type: !77)
+!77 = !DIDerivedType(tag: DW_TAG_ptr_to_member_type, baseType: !64, size: 64, flags: DIFlagSingleInheritance, extraData: !60)
+!78 = !DILocation(line: 33, column: 16, scope: !56)
+!79 = !DILocation(line: 34, column: 2, scope: !56)
+!80 = distinct !DISubprogram(name: "func", linkageName: "\01?func at Foo@?1??h@@YAXXZ at QEIAAHH@Z", scope: !60, file: !3, line: 24, type: !64, isLocal: true, isDefinition: true, scopeLine: 24, flags: DIFlagPrototyped, isOptimized: false, unit: !9, declaration: !63, variables: !10)
+!81 = !DILocalVariable(name: "x", arg: 2, scope: !80, file: !3, line: 24, type: !8)
+!82 = !DILocation(line: 24, column: 19, scope: !80)
+!83 = !DILocalVariable(name: "this", arg: 1, scope: !80, type: !84, flags: DIFlagArtificial | DIFlagObjectPointer)
+!84 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !67, size: 64)
+!85 = !DILocation(line: 0, scope: !80)
+!86 = !DILocation(line: 24, column: 35, scope: !80)




More information about the llvm-commits mailing list