Xiangling_L updated this revision to Diff 292537.
Xiangling_L added a comment.

Rebased on the pragma/pack patch;
Added packed related testcase for bitfield;


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87029/new/

https://reviews.llvm.org/D87029

Files:
  clang/lib/AST/RecordLayoutBuilder.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/test/Layout/aix-bitfield-alignment.cpp
  clang/test/Layout/aix-oversized-bitfield.cpp

Index: clang/test/Layout/aix-oversized-bitfield.cpp
===================================================================
--- /dev/null
+++ clang/test/Layout/aix-oversized-bitfield.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fsyntax-only -verify %s
+
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \
+// RUN:     -fsyntax-only %s | \
+// RUN:   FileCheck --check-prefix=CHECK64 %s
+
+struct A
+{
+    long long l : 64; // expected-error{{width of bit-field 'l' (64 bits) exceeds size of its type (32 bits)}}
+};
+
+int a = sizeof(A);
+
+// CHECK64:      *** Dumping AST Record Layout
+// CHECK64-NEXT:          0 | struct A
+// CHECK64-NEXT:     0:0-63 |   long long l
+// CHECK64-NEXT:            | [sizeof=8, dsize=8, align=8, preferredalign=8,
+// CHECK64-NEXT:            |  nvsize=8, nvalign=8, preferrednvalign=8]
Index: clang/test/Layout/aix-bitfield-alignment.cpp
===================================================================
--- /dev/null
+++ clang/test/Layout/aix-bitfield-alignment.cpp
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \
+// RUN:     -fsyntax-only  -x c++ %s | \
+// RUN:   FileCheck --check-prefixes=CHECK,CHECK32 %s
+
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \
+// RUN:     -fsyntax-only -x c++ %s | \
+// RUN:   FileCheck --check-prefixes=CHECK,CHECK64 %s
+
+struct A {
+  bool b : 3;
+  unsigned char c : 2;
+  unsigned short s : 6;
+};
+
+int a = sizeof(A);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct A
+// CHECK-NEXT:      0:0-2 |   _Bool b
+// CHECK-NEXT:      0:3-4 |   unsigned char c
+// CHECK-NEXT:     0:5-10 |   unsigned short s
+// CHECK-NEXT:            | [sizeof=4, dsize=4, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=4, nvalign=4, preferrednvalign=4]
+
+struct B {
+  char c;
+  int : 0;
+};
+
+int b = sizeof(B);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct B
+// CHECK-NEXT:          0 |   char c
+// CHECK-NEXT:        4:- |   int 
+// CHECK-NEXT:            | [sizeof=4, dsize=4, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=4, nvalign=4, preferrednvalign=4]
+
+struct C {
+  signed int a1 : 6;
+  signed char a2 : 4;
+  short int a3 : 2;
+  int a4 : 2;
+  signed long a5 : 5;
+  long long int a6 : 6;
+  unsigned long a7 : 8;
+};
+
+int c = sizeof(C);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct C
+// CHECK-NEXT:      0:0-5 |   int a1
+// CHECK-NEXT:      0:6-9 |   signed char a2
+// CHECK-NEXT:      1:2-3 |   short a3
+// CHECK-NEXT:      1:4-5 |   int a4
+// CHECK-NEXT:     1:6-10 |   long a5
+// CHECK-NEXT:      2:3-8 |   long long a6
+// CHECK32:         4:0-7 |   unsigned long a7
+// CHECK32:               | [sizeof=8, dsize=8, align=4, preferredalign=4,
+// CHECK32:               |  nvsize=8, nvalign=4, preferrednvalign=4]
+// CHECK64:         3:1-8 |   unsigned long a7
+// CHECK64:               | [sizeof=8, dsize=8, align=8, preferredalign=8,
+// CHECK64:               |  nvsize=8, nvalign=8, preferrednvalign=8]
+
+typedef __attribute__((aligned(32))) short mySHORT;
+struct D {
+  char c : 8;
+  mySHORT : 0;
+};
+
+int d = sizeof(D);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct D
+// CHECK-NEXT:      0:0-7 |   char c
+// CHECK-NEXT:       32:- |   mySHORT
+// CHECK-NEXT:            | [sizeof=32, dsize=32, align=32, preferredalign=32,
+// CHECK-NEXT:            |  nvsize=32, nvalign=32, preferrednvalign=32]
+
+enum class Bool : bool { False = 0,
+                         True = 1 };
+
+struct E {
+  Bool b : 1;
+};
+
+int e = sizeof(E);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct E
+// CHECK-NEXT:      0:0-0 |   enum Bool b
+// CHECK-NEXT:            | [sizeof=4, dsize=4, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=4, nvalign=4, preferrednvalign=4]
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -16443,7 +16443,22 @@
     bool MSBitfieldViolation =
         Value.ugt(TypeStorageSize) &&
         (IsMsStruct || Context.getTargetInfo().getCXXABI().isMicrosoft());
-    if (CStdConstraintViolation || MSBitfieldViolation) {
+
+    bool AIXBitfieldViolation = false;
+    if (const BuiltinType *BTy = FieldTy.getTypePtr()->getAs<BuiltinType>()) {
+      if ((BTy->getKind() == BuiltinType::ULongLong ||
+           BTy->getKind() == BuiltinType::LongLong) &&
+          (unsigned)Value.getZExtValue() > 32 &&
+          Context.getTargetInfo().getTriple().isArch32Bit() &&
+          Context.getTargetInfo().getTriple().getOS() == llvm::Triple::AIX) {
+        AIXBitfieldViolation = true;
+        TypeStorageSize = 32;
+        TypeWidth = 32;
+      }
+    }
+
+    if (CStdConstraintViolation || MSBitfieldViolation ||
+        AIXBitfieldViolation) {
       unsigned DiagWidth =
           CStdConstraintViolation ? TypeWidth : TypeStorageSize;
       if (FieldName)
Index: clang/lib/AST/RecordLayoutBuilder.cpp
===================================================================
--- clang/lib/AST/RecordLayoutBuilder.cpp
+++ clang/lib/AST/RecordLayoutBuilder.cpp
@@ -622,9 +622,9 @@
   /// an adjacent bitfield if necessary.  The unit in question is usually
   /// a byte, but larger units are used if IsMsStruct.
   unsigned char UnfilledBitsInLastUnit;
-  /// LastBitfieldTypeSize - If IsMsStruct, represents the size of the type
-  /// of the previous field if it was a bitfield.
-  unsigned char LastBitfieldTypeSize;
+  /// LastBitfieldStorageUnitSize - If IsMsStruct, represents the size of the
+  /// storage unit of the previous field if it was a bitfield.
+  unsigned char LastBitfieldStorageUnitSize;
 
   /// MaxFieldAlignment - The maximum allowed field alignment. This is set by
   /// #pragma pack.
@@ -693,7 +693,7 @@
         UnadjustedAlignment(CharUnits::One()), UseExternalLayout(false),
         InferAlignment(false), Packed(false), IsUnion(false),
         IsMac68kAlign(false), IsMsStruct(false), UnfilledBitsInLastUnit(0),
-        LastBitfieldTypeSize(0), MaxFieldAlignment(CharUnits::Zero()),
+        LastBitfieldStorageUnitSize(0), MaxFieldAlignment(CharUnits::Zero()),
         DataSize(0), NonVirtualSize(CharUnits::Zero()),
         NonVirtualAlignment(CharUnits::One()),
         PreferredNVAlignment(CharUnits::One()),
@@ -708,7 +708,7 @@
 
   void LayoutFields(const RecordDecl *D);
   void LayoutField(const FieldDecl *D, bool InsertExtraPadding);
-  void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize,
+  void LayoutWideBitField(uint64_t FieldSize, uint64_t StorageUnitSize,
                           bool FieldPacked, const FieldDecl *D);
   void LayoutBitField(const FieldDecl *D);
 
@@ -1451,7 +1451,7 @@
 }
 
 void ItaniumRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
-                                                    uint64_t TypeSize,
+                                                    uint64_t StorageUnitSize,
                                                     bool FieldPacked,
                                                     const FieldDecl *D) {
   assert(Context.getLangOpts().CPlusPlus &&
@@ -1481,7 +1481,7 @@
 
   // We're not going to use any of the unfilled bits in the last byte.
   UnfilledBitsInLastUnit = 0;
-  LastBitfieldTypeSize = 0;
+  LastBitfieldStorageUnitSize = 0;
 
   uint64_t FieldOffset;
   uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
@@ -1516,11 +1516,15 @@
   UpdateAlignment(TypeAlign);
 }
 
+static bool isAIXLayout(const ASTContext &Context) {
+  return Context.getTargetInfo().getTriple().getOS() == llvm::Triple::AIX;
+}
+
 void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
   bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
   uint64_t FieldSize = D->getBitWidthValue(Context);
   TypeInfo FieldInfo = Context.getTypeInfo(D->getType());
-  uint64_t TypeSize = FieldInfo.Width;
+  uint64_t StorageUnitSize = FieldInfo.Width;
   unsigned FieldAlign = FieldInfo.Align;
 
   // UnfilledBitsInLastUnit is the difference between the end of the
@@ -1529,7 +1533,7 @@
   // first bit offset available for non-bitfields).  The current data
   // size in bits is always a multiple of the char size; additionally,
   // for ms_struct records it's also a multiple of the
-  // LastBitfieldTypeSize (if set).
+  // LastBitfieldStorageUnitSize (if set).
 
   // The struct-layout algorithm is dictated by the platform ABI,
   // which in principle could use almost any rules it likes.  In
@@ -1583,26 +1587,64 @@
   // First, some simple bookkeeping to perform for ms_struct structs.
   if (IsMsStruct) {
     // The field alignment for integer types is always the size.
-    FieldAlign = TypeSize;
+    FieldAlign = StorageUnitSize;
 
     // If the previous field was not a bitfield, or was a bitfield
     // with a different storage unit size, or if this field doesn't fit into
     // the current storage unit, we're done with that storage unit.
-    if (LastBitfieldTypeSize != TypeSize ||
+    if (LastBitfieldStorageUnitSize != StorageUnitSize ||
         UnfilledBitsInLastUnit < FieldSize) {
       // Also, ignore zero-length bitfields after non-bitfields.
-      if (!LastBitfieldTypeSize && !FieldSize)
+      if (!LastBitfieldStorageUnitSize && !FieldSize)
         FieldAlign = 1;
 
       UnfilledBitsInLastUnit = 0;
-      LastBitfieldTypeSize = 0;
+      LastBitfieldStorageUnitSize = 0;
+    }
+  }
+
+  // On AIX, [bool, char, short] bitfields have the same alignment
+  // as [unsigned].
+  if (isAIXLayout(Context)) {
+    const BuiltinType *BTy = nullptr;
+
+    // Get the underlying type from EnumDecl.
+    if (const EnumType *ET = dyn_cast<EnumType>(D->getType().getTypePtr())) {
+      const EnumDecl *ED = ET->getDecl();
+      if (const BuiltinType *BT =
+              dyn_cast<BuiltinType>(ED->getPromotionType().getTypePtr()))
+        BTy = BT;
+    } else {
+      BTy = Context.getBaseElementType(D->getType())->getAs<BuiltinType>();
+    }
+
+    if (BTy) {
+      BuiltinType::Kind BTyKind = BTy->getKind();
+      if (BTyKind != BuiltinType::ULong && BTyKind != BuiltinType::Long &&
+          BTyKind != BuiltinType::ULongLong &&
+          BTyKind != BuiltinType::LongLong) {
+        // Only set bitfields alignment to unsigned when it does
+        // not have attribute align specified or is less than
+        // unsigned alignment.
+        if (FieldAlign < Context.getTypeSize(Context.UnsignedIntTy))
+          FieldAlign = Context.getTypeSize(Context.UnsignedIntTy);
+        StorageUnitSize = Context.getTypeSize(Context.UnsignedIntTy);
+      } else {
+        // Handle AIX oversized Long Long bitfield under 32 bit compile mode.
+        if (StorageUnitSize > 32 &&
+            Context.getTargetInfo().getTriple().isArch32Bit()) {
+          StorageUnitSize = 32;
+          FieldAlign = 32;
+        }
+      }
     }
   }
 
   // If the field is wider than its declared type, it follows
-  // different rules in all cases.
-  if (FieldSize > TypeSize) {
-    LayoutWideBitField(FieldSize, TypeSize, FieldPacked, D);
+  // different rules in all cases, except on AIX.
+  // On AIX, wide bitfield follows the same rules as normal bitfield.
+  if (FieldSize > StorageUnitSize) {
+    LayoutWideBitField(FieldSize, StorageUnitSize, FieldPacked, D);
     return;
   }
 
@@ -1686,7 +1728,7 @@
     // Compute the real offset.
     if (FieldSize == 0 ||
         (AllowPadding &&
-         (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)) {
+         (FieldOffset & (FieldAlign - 1)) + FieldSize > StorageUnitSize)) {
       FieldOffset = llvm::alignTo(FieldOffset, FieldAlign);
     } else if (ExplicitFieldAlign &&
                (MaxFieldAlignmentInBits == 0 ||
@@ -1700,7 +1742,8 @@
     // Repeat the computation for diagnostic purposes.
     if (FieldSize == 0 ||
         (AllowPadding &&
-         (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize))
+         (UnpackedFieldOffset & (UnpackedFieldAlign - 1)) + FieldSize >
+             StorageUnitSize))
       UnpackedFieldOffset =
           llvm::alignTo(UnpackedFieldOffset, UnpackedFieldAlign);
     else if (ExplicitFieldAlign &&
@@ -1741,11 +1784,11 @@
     // is a zero-width bitfield, in which case just use a size of 1.
     uint64_t RoundedFieldSize;
     if (IsMsStruct) {
-      RoundedFieldSize =
-        (FieldSize ? TypeSize : Context.getTargetInfo().getCharWidth());
+      RoundedFieldSize = (FieldSize ? StorageUnitSize
+                                    : Context.getTargetInfo().getCharWidth());
 
-    // Otherwise, allocate just the number of bytes required to store
-    // the bitfield.
+      // Otherwise, allocate just the number of bytes required to store
+      // the bitfield.
     } else {
       RoundedFieldSize = roundUpSizeToCharAlignment(FieldSize, Context);
     }
@@ -1757,15 +1800,15 @@
     // We should have cleared UnfilledBitsInLastUnit in every case
     // where we changed storage units.
     if (!UnfilledBitsInLastUnit) {
-      setDataSize(FieldOffset + TypeSize);
-      UnfilledBitsInLastUnit = TypeSize;
+      setDataSize(FieldOffset + StorageUnitSize);
+      UnfilledBitsInLastUnit = StorageUnitSize;
     }
     UnfilledBitsInLastUnit -= FieldSize;
-    LastBitfieldTypeSize = TypeSize;
+    LastBitfieldStorageUnitSize = StorageUnitSize;
 
-  // Otherwise, bump the data size up to include the bitfield,
-  // including padding up to char alignment, and then remember how
-  // bits we didn't use.
+    // Otherwise, bump the data size up to include the bitfield,
+    // including padding up to char alignment, and then remember how
+    // bits we didn't use.
   } else {
     uint64_t NewSizeInBits = FieldOffset + FieldSize;
     uint64_t CharAlignment = Context.getTargetInfo().getCharAlign();
@@ -1775,7 +1818,7 @@
     // The only time we can get here for an ms_struct is if this is a
     // zero-width bitfield, which doesn't count as anything for the
     // purposes of unfilled bits.
-    LastBitfieldTypeSize = 0;
+    LastBitfieldStorageUnitSize = 0;
   }
 
   // Update the size.
@@ -1825,7 +1868,7 @@
   uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
   // Reset the unfilled bits.
   UnfilledBitsInLastUnit = 0;
-  LastBitfieldTypeSize = 0;
+  LastBitfieldStorageUnitSize = 0;
 
   bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to