jmmartinez created this revision.
jmmartinez added reviewers: dblaikie, probinson.
Herald added subscribers: kosarev, tpr.
Herald added a project: All.
jmmartinez requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

I'm looking for some feedback, this is definitively not the final solution.
I was wondering if there was an alternative to pass this information in the 
dwarf debug-info.

Consider the following sturctures when targetting:

  struct foo {
    int space[4];
    char a : 8;
    char b : 8;
    char x : 8;
    char y : 8;
  };
  
  struct bar {
    int space[4];
    char a : 8;
    char b : 8;
    char : 0;
    char x : 8;
    char y : 8;
  };

Even if both structs have the same layout in memory, they are handled
differenlty by the AMDGPU ABI.

With the following code:

// clang --target=amdgcn-amd-amdhsa -g -O1 example.c -S
char use_foo(struct foo f) { return f.y; }
char use_bar(struct bar b) { return b.y; }

For use_foo, the 'y' field is passed in v4
; v_ashrrev_i32_e32 v0, 24, v4
; s_setpc_b64 s[30:31]

For use_bar, the 'y' field is passed in v5
; v_bfe_i32 v0, v5, 8, 8
; s_setpc_b64 s[30:31]

To make this distinction, we record a single 0-size bitfield for every member 
that is preceded
by it.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D144870

Files:
  clang/lib/CodeGen/CGDebugInfo.cpp
  clang/lib/CodeGen/CGDebugInfo.h
  clang/lib/CodeGen/CGRecordLayout.h
  clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
  clang/test/CodeGen/debug-info-bitfield-0-struct.c

Index: clang/test/CodeGen/debug-info-bitfield-0-struct.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/debug-info-bitfield-0-struct.c
@@ -0,0 +1,97 @@
+// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=limited %s | FileCheck %s
+
+struct First {
+  // CHECK-DAG: ![[FIRST:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "First", file: !{{[0-9]+}}, line: {{[0-9]+}}, size: 32, elements: ![[FIRST_ELEMENTS:[0-9]+]])
+  // CHECK-DAG: ![[FIRST_ELEMENTS]] = !{![[FIRST_X:[0-9]+]], ![[FIRST_Y:[0-9]+]]}
+  // CHECK-DAG: ![[FIRST_X]] = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: ![[FIRST]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, flags: DIFlagBitField, extraData: i64 0)
+  // CHECK-DAG: ![[FIRST_Y]] = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: ![[FIRST]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, offset: 4, flags: DIFlagBitField, extraData: i64 0)
+  int : 0;
+  int x : 4;
+  int y : 4;
+};
+
+struct FirstDuplicate {
+  // CHECK-DAG: ![[FIRSTD:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "FirstDuplicate", file: !{{[0-9]+}}, line: {{[0-9]+}}, size: 32, elements: ![[FIRSTD_ELEMENTS:[0-9]+]])
+  // CHECK-DAG: ![[FIRSTD_ELEMENTS]] = !{![[FIRSTD_X:[0-9]+]], ![[FIRSTD_Y:[0-9]+]]}
+  // CHECK-DAG: ![[FIRSTD_X]] = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: ![[FIRSTD]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, flags: DIFlagBitField, extraData: i64 0)
+  // CHECK-DAG: ![[FIRSTD_Y]] = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: ![[FIRSTD]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, offset: 4, flags: DIFlagBitField, extraData: i64 0)
+  int : 0;
+  int : 0;
+  int x : 4;
+  int y : 4;
+};
+
+struct Second {
+  // CHECK-DAG: ![[SECOND:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Second", file: !{{[0-9]+}}, line: {{[0-9]+}}, size: 64, elements: ![[SECOND_ELEMENTS:[0-9]+]])
+  // CHECK-DAG: ![[SECOND_ELEMENTS]] = !{![[SECOND_X:[0-9]+]], ![[SECOND_ZERO:[0-9]+]], ![[SECOND_Y:[0-9]+]]}
+  // CHECK-DAG: ![[SECOND_X]] = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: ![[SECOND]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, flags: DIFlagBitField, extraData: i64 0)
+  // CHECK-DAG: ![[SECOND_ZERO]] = !DIDerivedType(tag: DW_TAG_member, scope: ![[SECOND]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+  // CHECK-DAG: ![[SECOND_Y]] = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: ![[SECOND]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+  int x : 4;
+  int : 0;
+  int y : 4;
+};
+
+struct SecondDuplicate {
+  // CHECK-DAG: ![[SECONDD:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "SecondDuplicate", file: !{{[0-9]+}}, line: {{[0-9]+}}, size: 64, elements: ![[SECONDD_ELEMENTS:[0-9]+]])
+  // CHECK-DAG: ![[SECONDD_ELEMENTS]] = !{![[SECONDD_X:[0-9]+]], ![[SECONDD_ZERO:[0-9]+]], ![[SECONDD_Y:[0-9]+]]}
+  // CHECK-DAG: ![[SECONDD_X]] = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: ![[SECONDD]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, flags: DIFlagBitField, extraData: i64 0)
+  // CHECK-DAG: ![[SECONDD_ZERO]] = !DIDerivedType(tag: DW_TAG_member, scope: ![[SECONDD]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+  // CHECK-DAG: ![[SECONDD_Y]] = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: ![[SECONDD]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+  int x : 4;
+  int : 0;
+  int : 0;
+  int y : 4;
+};
+
+struct Last {
+  // CHECK-DAG: ![[LAST:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Last", file: !{{[0-9]+}}, line: {{[0-9]+}}, size: 32, elements: ![[LAST_ELEMENTS:[0-9]+]])
+  // CHECK-DAG: ![[LAST_ELEMENTS]] = !{![[LAST_X:[0-9]+]], ![[LAST_Y:[0-9]+]]}
+  // CHECK-DAG: ![[LAST_X]] = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: ![[LAST]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, flags: DIFlagBitField, extraData: i64 0)
+  // CHECK-DAG: ![[LAST_Y]] = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: ![[LAST]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, offset: 4, flags: DIFlagBitField, extraData: i64 0)
+  int x : 4;
+  int y : 4;
+  int : 0;
+};
+
+struct Several {
+  // CHECK-DAG: ![[SEVERAL:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Several", file: !{{[0-9]+}}, line: {{[0-9]+}}, size: 96, elements: ![[SEVERAL_ELEMENTS:[0-9]+]])
+  // CHECK-DAG: ![[SEVERAL_ELEMENTS]] = !{![[SEVERAL_X:[0-9]+]], ![[SEVERAL_FIRST_ZERO:[0-9]+]], ![[SEVERAL_Y:[0-9]+]], ![[SEVERAL_SECOND_ZERO:[0-9]+]], ![[SEVERAL_Z:[0-9]+]]}
+  // CHECK-DAG: ![[SEVERAL_X]] = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: ![[SEVERAL]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, flags: DIFlagBitField, extraData: i64 0)
+  // CHECK-DAG: ![[SEVERAL_FIRST_ZERO]] = !DIDerivedType(tag: DW_TAG_member, scope: ![[SEVERAL]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+  // CHECK-DAG: ![[SEVERAL_Y]] = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: ![[SEVERAL]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+  // CHECK-DAG: ![[SEVERAL_SECOND_ZERO]] = !DIDerivedType(tag: DW_TAG_member, scope: ![[SEVERAL]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, offset: 64, flags: DIFlagBitField, extraData: i64 64)
+  // CHECK-DAG: ![[SEVERAL_Z]] = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: ![[SEVERAL]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, offset: 64, flags: DIFlagBitField, extraData: i64 64)
+  int x : 4;
+  int : 0;
+  int y : 4;
+  int : 0;
+  int z : 4;
+};
+
+struct None {
+  // CHECK-DAG: ![[NONE:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "None", file: !{{[0-9]+}}, line: {{[0-9]+}}, size: 64, elements: ![[NONE_ELEMENTS:[0-9]+]])
+  // CHECK-DAG: ![[NONE_ELEMENTS]] = !{![[NONE_FIELD:[0-9]+]], ![[NONE_X:[0-9]+]]}
+  // CHECK-DAG: ![[NONE_FIELD]] = !DIDerivedType(tag: DW_TAG_member, name: "field", scope: ![[NONE]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 32)
+  // CHECK-DAG: ![[NONE_X]] = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: ![[NONE]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+  int : 0;
+  int field;
+  int x : 4;
+};
+
+struct Mixed {
+  // CHECK-DAG: ![[MIXED:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Mixed", file: !{{[0-9]+}}, line: {{[0-9]+}}, size: 64, elements: ![[MIXED_ELEMENTS:[0-9]+]])
+  // CHECK-DAG: ![[MIXED_ELEMENTS]] = !{![[MIXED_FIELD:[0-9]+]], ![[MIXED_ZERO:[0-9]+]], ![[MIXED_X:[0-9]+]], ![[MIXED_Y:[0-9]+]]}
+  // CHECK-DAG: ![[MIXED_FIELD]] = !DIDerivedType(tag: DW_TAG_member, name: "field", scope: ![[MIXED]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 32)
+  // CHECK-DAG: ![[MIXED_ZERO]] = !DIDerivedType(tag: DW_TAG_member, scope: ![[MIXED]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+  // CHECK-DAG: ![[MIXED_X]] = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: ![[MIXED]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, offset: 32, flags: DIFlagBitField, extraData: i64 32)
+  // CHECK-DAG: ![[MIXED_Y]] = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: ![[MIXED]], file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: !{{[0-9]+}}, size: 4, offset: 36, flags: DIFlagBitField, extraData: i64 32)
+  int field;
+  int : 0;
+  int x : 4;
+  int y : 4;
+};
+
+void foo(struct First f, struct FirstDuplicate fs, struct Second s, struct SecondDuplicate sd, struct Last l, struct Several ss, struct None n, struct Mixed m) {
+  return;
+}
Index: clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
===================================================================
--- clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -10,8 +10,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "CGRecordLayout.h"
 #include "CGCXXABI.h"
+#include "CGRecordLayout.h"
 #include "CodeGenTypes.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Attr.h"
@@ -465,6 +465,8 @@
 
   // The start field is better as a single field run.
   bool StartFieldAsSingleRun = false;
+  FieldDecl *ZeroBitfieldStartingRun = nullptr;
+
   for (;;) {
     // Check to see if we need to start a new run.
     if (Run == FieldEnd) {
@@ -478,6 +480,15 @@
         Tail = StartBitOffset + Field->getBitWidthValue(Context);
         StartFieldAsSingleRun = IsBetterAsSingleFieldRun(Tail - StartBitOffset,
                                                          StartBitOffset);
+
+        if (ZeroBitfieldStartingRun) {
+          BitFields[*Field].setRunStartedBy0Length0BitField(
+              ZeroBitfieldStartingRun);
+          ZeroBitfieldStartingRun = nullptr;
+        }
+      } else {
+        if (getFieldBitOffset(*Field) != 0)
+          ZeroBitfieldStartingRun = *Field;
       }
       ++Field;
       continue;
@@ -487,7 +498,6 @@
     // if current field (or consecutive fields) is better as a single run, or
     // if current field has zero width bitfield and either
     // UseZeroLengthBitfieldAlignment or UseBitFieldTypeAlignment is set to
-    // true, or
     // if the offset of current field is inconsistent with the offset of
     // previous field plus its offset,
     // skip the block below and go ahead to emit the storage.
@@ -1057,7 +1067,9 @@
      << " StorageOffset:" << StorageOffset.getQuantity()
      << " VolatileOffset:" << VolatileOffset
      << " VolatileStorageSize:" << VolatileStorageSize
-     << " VolatileStorageOffset:" << VolatileStorageOffset.getQuantity() << ">";
+     << " VolatileStorageOffset:" << VolatileStorageOffset.getQuantity()
+     << " RunStarteddByLenght0BitField:"
+     << (RunStartedBy0LenghtBitField ? "true" : "false") << ">";
 }
 
 LLVM_DUMP_METHOD void CGBitFieldInfo::dump() const {
Index: clang/lib/CodeGen/CGRecordLayout.h
===================================================================
--- clang/lib/CodeGen/CGRecordLayout.h
+++ clang/lib/CodeGen/CGRecordLayout.h
@@ -92,14 +92,24 @@
   /// The offset of the bitfield storage from the start of the struct.
   CharUnits VolatileStorageOffset;
 
+  /// On AMDGPU, the calling convention states that adjacent bitfields
+  /// (not separated by a 0-length annonymous bitfield) are considered as a
+  /// whole field passed together in the same register.
+  FieldDecl *RunStartedBy0LenghtBitField;
+
   CGBitFieldInfo()
       : Offset(), Size(), IsSigned(), StorageSize(), VolatileOffset(),
-        VolatileStorageSize() {}
+        VolatileStorageSize(), RunStartedBy0LenghtBitField(nullptr) {}
 
   CGBitFieldInfo(unsigned Offset, unsigned Size, bool IsSigned,
                  unsigned StorageSize, CharUnits StorageOffset)
       : Offset(Offset), Size(Size), IsSigned(IsSigned),
-        StorageSize(StorageSize), StorageOffset(StorageOffset) {}
+        StorageSize(StorageSize), StorageOffset(StorageOffset),
+        RunStartedBy0LenghtBitField(nullptr) {}
+
+  void setRunStartedBy0Length0BitField(FieldDecl *Zero) {
+    RunStartedBy0LenghtBitField = Zero;
+  }
 
   void print(raw_ostream &OS) const;
   void dump() const;
Index: clang/lib/CodeGen/CGDebugInfo.h
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.h
+++ clang/lib/CodeGen/CGDebugInfo.h
@@ -321,11 +321,16 @@
                            RD);
   }
 
-  /// Create new bit field member.
+  /// Create new bit field member and zero-size separator if needed.
   llvm::DIType *createBitFieldType(const FieldDecl *BitFieldDecl,
                                    llvm::DIScope *RecordTy,
                                    const RecordDecl *RD);
 
+  llvm::DIType *
+  createBitFieldZeroLengthSeparatorType(const FieldDecl *BitFieldDecl,
+                                        llvm::DIScope *RecordTy,
+                                        const RecordDecl *RD);
+
   /// Helpers for collecting fields of a record.
   /// @{
   void CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
Index: clang/lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.cpp
+++ clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1466,6 +1466,35 @@
   return F;
 }
 
+llvm::DIType *CGDebugInfo::createBitFieldZeroLengthSeparatorType(
+    const FieldDecl *BitFieldDecl, llvm::DIScope *RecordTy,
+    const RecordDecl *RD) {
+  const CGBitFieldInfo &BitFieldInfo =
+      CGM.getTypes().getCGRecordLayout(RD).getBitFieldInfo(BitFieldDecl);
+
+  FieldDecl *ZeroLengthSeparator = BitFieldInfo.RunStartedBy0LenghtBitField;
+  if (!ZeroLengthSeparator)
+    return nullptr;
+
+  // This bitfield doesn't really exist in practice. Make it point to the
+  // begining of the storage offset (the word in the struct). This works for any
+  // endianness.
+  uint64_t StorageOffsetInBits =
+      CGM.getContext().toBits(BitFieldInfo.StorageOffset);
+  uint64_t OffsetInBits = StorageOffsetInBits;
+
+  QualType Ty = ZeroLengthSeparator->getType();
+  SourceLocation Loc = ZeroLengthSeparator->getLocation();
+  llvm::DIFile *VUnit = getOrCreateFile(Loc);
+  llvm::DIType *DebugType = getOrCreateType(Ty, VUnit);
+
+  llvm::DIFile *File = getOrCreateFile(Loc);
+  unsigned ZeroLine = getLineNumber(Loc);
+  return DBuilder.createBitFieldMemberType(
+      RecordTy, "", File, ZeroLine, 0, OffsetInBits, StorageOffsetInBits,
+      llvm::DINode::DIFlags::FlagZero, DebugType, {});
+}
+
 llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl,
                                               llvm::DIScope *RecordTy,
                                               const RecordDecl *RD) {
@@ -1607,6 +1636,9 @@
 
   llvm::DIType *FieldType;
   if (field->isBitField()) {
+    if (llvm::DIType *RunSeparator =
+            createBitFieldZeroLengthSeparatorType(field, RecordTy, RD))
+      elements.push_back(RunSeparator);
     FieldType = createBitFieldType(field, RecordTy, RD);
   } else {
     auto Align = getDeclAlignIfRequired(field, CGM.getContext());
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D144... Juan Manuel Martinez Caamaño via Phabricator via cfe-commits
    • [PATCH]... David Blaikie via Phabricator via cfe-commits
    • [PATCH]... Juan Manuel Martinez Caamaño via Phabricator via cfe-commits
    • [PATCH]... Paul Robinson via Phabricator via cfe-commits
    • [PATCH]... Juan Manuel Martinez Caamaño via Phabricator via cfe-commits
    • [PATCH]... Juan Manuel Martinez Caamaño via Phabricator via cfe-commits

Reply via email to