[AIX] Implement AIX special alignment rule about double/long double
authorXiangling Liao <Xiangling.Liao@ibm.com>
Tue, 2 Jun 2020 15:51:58 +0000 (11:51 -0400)
committerXiangling Liao <Xiangling.Liao@ibm.com>
Mon, 27 Jul 2020 19:13:03 +0000 (15:13 -0400)
Implement AIX default `power` alignment rule by adding `PreferredAlignment` and
`PreferredNVAlignment` in ASTRecordLayout class.

The patchh aims at returning correct value for `__alignof(x)` and `alignof(x)`
under `power` alignment rules.

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

15 files changed:
clang/include/clang/AST/RecordLayout.h
clang/include/clang/Basic/TargetInfo.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/RecordLayout.cpp
clang/lib/AST/RecordLayoutBuilder.cpp
clang/lib/Basic/Targets/OSTargets.h
clang/lib/Basic/Targets/PPC.h
clang/test/Layout/aix-Wpacked-expecting-diagnostics.cpp [new file with mode: 0644]
clang/test/Layout/aix-Wpacked-no-diagnostics.cpp [new file with mode: 0644]
clang/test/Layout/aix-double-struct-member.cpp [new file with mode: 0644]
clang/test/Layout/aix-no-unique-address-with-double.cpp [new file with mode: 0644]
clang/test/Layout/aix-pack-attr-on-base.cpp [new file with mode: 0644]
clang/test/Layout/aix-power-alignment-typedef-2.cpp [new file with mode: 0644]
clang/test/Layout/aix-power-alignment-typedef.cpp [new file with mode: 0644]
clang/test/Layout/aix-virtual-function-and-base-with-double.cpp [new file with mode: 0644]

index b259791..946fbd8 100644 (file)
@@ -70,6 +70,11 @@ private:
   // Alignment - Alignment of record in characters.
   CharUnits Alignment;
 
+  // PreferredAlignment - Preferred alignment of record in characters. This
+  // can be different than Alignment in cases where it is beneficial for
+  // performance or backwards compatibility preserving (e.g. AIX-ABI).
+  CharUnits PreferredAlignment;
+
   // UnadjustedAlignment - Maximum of the alignments of the record members in
   // characters.
   CharUnits UnadjustedAlignment;
@@ -91,6 +96,11 @@ private:
     /// which is the alignment of the object without virtual bases.
     CharUnits NonVirtualAlignment;
 
+    /// PreferredNVAlignment - The preferred non-virtual alignment (in chars) of
+    /// an object, which is the preferred alignment of the object without
+    /// virtual bases.
+    CharUnits PreferredNVAlignment;
+
     /// SizeOfLargestEmptySubobject - The size of the largest empty subobject
     /// (either a base or a member). Will be zero if the class doesn't contain
     /// any empty subobjects.
@@ -139,30 +149,26 @@ private:
   CXXRecordLayoutInfo *CXXInfo = nullptr;
 
   ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
-                  CharUnits unadjustedAlignment,
+                  CharUnits preferredAlignment, CharUnits unadjustedAlignment,
                   CharUnits requiredAlignment, CharUnits datasize,
                   ArrayRef<uint64_t> fieldoffsets);
 
   using BaseOffsetsMapTy = CXXRecordLayoutInfo::BaseOffsetsMapTy;
 
   // Constructor for C++ records.
-  ASTRecordLayout(const ASTContext &Ctx,
-                  CharUnits size, CharUnits alignment,
-                  CharUnits unadjustedAlignment,
-                  CharUnits requiredAlignment,
-                  bool hasOwnVFPtr, bool hasExtendableVFPtr,
-                  CharUnits vbptroffset,
-                  CharUnits datasize,
-                  ArrayRef<uint64_t> fieldoffsets,
+  ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
+                  CharUnits preferredAlignment, CharUnits unadjustedAlignment,
+                  CharUnits requiredAlignment, bool hasOwnVFPtr,
+                  bool hasExtendableVFPtr, CharUnits vbptroffset,
+                  CharUnits datasize, ArrayRef<uint64_t> fieldoffsets,
                   CharUnits nonvirtualsize, CharUnits nonvirtualalignment,
+                  CharUnits preferrednvalignment,
                   CharUnits SizeOfLargestEmptySubobject,
-                  const CXXRecordDecl *PrimaryBase,
-                  bool IsPrimaryBaseVirtual,
+                  const CXXRecordDecl *PrimaryBase, bool IsPrimaryBaseVirtual,
                   const CXXRecordDecl *BaseSharingVBPtr,
-                  bool EndsWithZeroSizedObject,
-                  bool LeadsWithZeroSizedBase,
-                  const BaseOffsetsMapTy& BaseOffsets,
-                  const VBaseOffsetsMapTy& VBaseOffsets);
+                  bool EndsWithZeroSizedObject, bool LeadsWithZeroSizedBase,
+                  const BaseOffsetsMapTy &BaseOffsets,
+                  const VBaseOffsetsMapTy &VBaseOffsets);
 
   ~ASTRecordLayout() = default;
 
@@ -175,6 +181,10 @@ public:
   /// getAlignment - Get the record alignment in characters.
   CharUnits getAlignment() const { return Alignment; }
 
+  /// getPreferredFieldAlignment - Get the record preferred alignment in
+  /// characters.
+  CharUnits getPreferredAlignment() const { return PreferredAlignment; }
+
   /// getUnadjustedAlignment - Get the record alignment in characters, before
   /// alignment adjustement.
   CharUnits getUnadjustedAlignment() const { return UnadjustedAlignment; }
@@ -193,9 +203,7 @@ public:
 
   /// getDataSize() - Get the record data size, which is the record size
   /// without tail padding, in characters.
-  CharUnits getDataSize() const {
-    return DataSize;
-  }
+  CharUnits getDataSize() const { return DataSize; }
 
   /// getNonVirtualSize - Get the non-virtual size (in chars) of an object,
   /// which is the size of the object without virtual bases.
@@ -205,14 +213,23 @@ public:
     return CXXInfo->NonVirtualSize;
   }
 
-  /// getNonVirtualSize - Get the non-virtual alignment (in chars) of an object,
-  /// which is the alignment of the object without virtual bases.
+  /// getNonVirtualAlignment - Get the non-virtual alignment (in chars) of an
+  /// object, which is the alignment of the object without virtual bases.
   CharUnits getNonVirtualAlignment() const {
     assert(CXXInfo && "Record layout does not have C++ specific info!");
 
     return CXXInfo->NonVirtualAlignment;
   }
 
+  /// getPreferredNVAlignment - Get the preferred non-virtual alignment (in
+  /// chars) of an object, which is the preferred alignment of the object
+  /// without virtual bases.
+  CharUnits getPreferredNVAlignment() const {
+    assert(CXXInfo && "Record layout does not have C++ specific info!");
+
+    return CXXInfo->PreferredNVAlignment;
+  }
+
   /// getPrimaryBase - Get the primary base for this record.
   const CXXRecordDecl *getPrimaryBase() const {
     assert(CXXInfo && "Record layout does not have C++ specific info!");
@@ -287,9 +304,7 @@ public:
     return !CXXInfo->VBPtrOffset.isNegative();
   }
 
-  CharUnits getRequiredAlignment() const {
-    return RequiredAlignment;
-  }
+  CharUnits getRequiredAlignment() const { return RequiredAlignment; }
 
   bool endsWithZeroSizedObject() const {
     return CXXInfo && CXXInfo->EndsWithZeroSizedObject;
index 2ee3b16..004990e 100644 (file)
@@ -1401,6 +1401,9 @@ public:
   /// Whether target allows to overalign ABI-specified preferred alignment
   virtual bool allowsLargerPreferedTypeAlignment() const { return true; }
 
+  /// Whether target defaults to the `power` alignment rules of AIX.
+  virtual bool defaultsToAIXPowerAlignment() const { return false; }
+
   /// Set supported OpenCL extensions and optional core features.
   virtual void setSupportedOpenCLOpts() {}
 
index fc76317..e7518a5 100644 (file)
@@ -2439,8 +2439,8 @@ CharUnits ASTContext::getTypeUnadjustedAlignInChars(const Type *T) const {
 
 /// getPreferredTypeAlign - Return the "preferred" alignment of the specified
 /// type for the current target in bits.  This can be different than the ABI
-/// alignment in cases where it is beneficial for performance to overalign
-/// a data type.
+/// alignment in cases where it is beneficial for performance or backwards
+/// compatibility preserving to overalign a data type.
 unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
   TypeInfo TI = getTypeInfo(T);
   unsigned ABIAlign = TI.Align;
@@ -2450,18 +2450,33 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
   // The preferred alignment of member pointers is that of a pointer.
   if (T->isMemberPointerType())
     return getPreferredTypeAlign(getPointerDiffType().getTypePtr());
-
   if (!Target->allowsLargerPreferedTypeAlignment())
     return ABIAlign;
 
-  // Double and long long should be naturally aligned if possible.
+  if (const auto *RT = T->getAs<RecordType>()) {
+    if (TI.AlignIsRequired)
+      return ABIAlign;
+
+    unsigned PreferredAlign = static_cast<unsigned>(
+        toBits(getASTRecordLayout(RT->getDecl()).PreferredAlignment));
+    assert(PreferredAlign >= ABIAlign &&
+           "PreferredAlign should be at least as large as ABIAlign.");
+    return PreferredAlign;
+  }
+
+  // Double (and, for targets supporting AIX `power` alignment, long double) and
+  // long long should be naturally aligned (despite requiring less alignment) if
+  // possible.
   if (const auto *CT = T->getAs<ComplexType>())
     T = CT->getElementType().getTypePtr();
   if (const auto *ET = T->getAs<EnumType>())
     T = ET->getDecl()->getIntegerType().getTypePtr();
   if (T->isSpecificBuiltinType(BuiltinType::Double) ||
       T->isSpecificBuiltinType(BuiltinType::LongLong) ||
-      T->isSpecificBuiltinType(BuiltinType::ULongLong))
+      T->isSpecificBuiltinType(BuiltinType::ULongLong) ||
+      (T->isSpecificBuiltinType(BuiltinType::LongDouble) &&
+       Target->defaultsToAIXPowerAlignment()))
     // Don't increase the alignment if an alignment attribute was specified on a
     // typedef declaration.
     if (!TI.AlignIsRequired)
index e7b500e..8f70a20 100644 (file)
@@ -29,45 +29,42 @@ void ASTRecordLayout::Destroy(ASTContext &Ctx) {
 
 ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size,
                                  CharUnits alignment,
+                                 CharUnits preferredAlignment,
                                  CharUnits unadjustedAlignment,
                                  CharUnits requiredAlignment,
                                  CharUnits datasize,
                                  ArrayRef<uint64_t> fieldoffsets)
     : Size(size), DataSize(datasize), Alignment(alignment),
+      PreferredAlignment(preferredAlignment),
       UnadjustedAlignment(unadjustedAlignment),
       RequiredAlignment(requiredAlignment) {
   FieldOffsets.append(Ctx, fieldoffsets.begin(), fieldoffsets.end());
 }
 
 // Constructor for C++ records.
-ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
-                                 CharUnits size, CharUnits alignment,
-                                 CharUnits unadjustedAlignment,
-                                 CharUnits requiredAlignment,
-                                 bool hasOwnVFPtr, bool hasExtendableVFPtr,
-                                 CharUnits vbptroffset,
-                                 CharUnits datasize,
-                                 ArrayRef<uint64_t> fieldoffsets,
-                                 CharUnits nonvirtualsize,
-                                 CharUnits nonvirtualalignment,
-                                 CharUnits SizeOfLargestEmptySubobject,
-                                 const CXXRecordDecl *PrimaryBase,
-                                 bool IsPrimaryBaseVirtual,
-                                 const CXXRecordDecl *BaseSharingVBPtr,
-                                 bool EndsWithZeroSizedObject,
-                                 bool LeadsWithZeroSizedBase,
-                                 const BaseOffsetsMapTy& BaseOffsets,
-                                 const VBaseOffsetsMapTy& VBaseOffsets)
-  : Size(size), DataSize(datasize), Alignment(alignment),
-    UnadjustedAlignment(unadjustedAlignment),
-    RequiredAlignment(requiredAlignment), CXXInfo(new (Ctx) CXXRecordLayoutInfo)
-{
+ASTRecordLayout::ASTRecordLayout(
+    const ASTContext &Ctx, CharUnits size, CharUnits alignment,
+    CharUnits preferredAlignment, CharUnits unadjustedAlignment,
+    CharUnits requiredAlignment, bool hasOwnVFPtr, bool hasExtendableVFPtr,
+    CharUnits vbptroffset, CharUnits datasize, ArrayRef<uint64_t> fieldoffsets,
+    CharUnits nonvirtualsize, CharUnits nonvirtualalignment,
+    CharUnits preferrednvalignment, CharUnits SizeOfLargestEmptySubobject,
+    const CXXRecordDecl *PrimaryBase, bool IsPrimaryBaseVirtual,
+    const CXXRecordDecl *BaseSharingVBPtr, bool EndsWithZeroSizedObject,
+    bool LeadsWithZeroSizedBase, const BaseOffsetsMapTy &BaseOffsets,
+    const VBaseOffsetsMapTy &VBaseOffsets)
+    : Size(size), DataSize(datasize), Alignment(alignment),
+      PreferredAlignment(preferredAlignment),
+      UnadjustedAlignment(unadjustedAlignment),
+      RequiredAlignment(requiredAlignment),
+      CXXInfo(new (Ctx) CXXRecordLayoutInfo) {
   FieldOffsets.append(Ctx, fieldoffsets.begin(), fieldoffsets.end());
 
   CXXInfo->PrimaryBase.setPointer(PrimaryBase);
   CXXInfo->PrimaryBase.setInt(IsPrimaryBaseVirtual);
   CXXInfo->NonVirtualSize = nonvirtualsize;
   CXXInfo->NonVirtualAlignment = nonvirtualalignment;
+  CXXInfo->PreferredNVAlignment = preferrednvalignment;
   CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject;
   CXXInfo->BaseOffsets = BaseOffsets;
   CXXInfo->VBaseOffsets = VBaseOffsets;
index d56c7e2..0afe91b 100644 (file)
@@ -6,7 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/AST/RecordLayout.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTDiagnostic.h"
 #include "clang/AST/Attr.h"
@@ -16,6 +15,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/VTableBuilder.h"
+#include "clang/AST/RecordLayout.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/Support/Format.h"
@@ -589,6 +589,9 @@ protected:
   /// Alignment - The current alignment of the record layout.
   CharUnits Alignment;
 
+  /// PreferredAlignment - The preferred alignment of the record layout.
+  CharUnits PreferredAlignment;
+
   /// The alignment if attribute packed is not used.
   CharUnits UnpackedAlignment;
 
@@ -632,6 +635,7 @@ protected:
 
   CharUnits NonVirtualSize;
   CharUnits NonVirtualAlignment;
+  CharUnits PreferredNVAlignment;
 
   /// If we've laid out a field but not included its tail padding in Size yet,
   /// this is the size up to the end of that field.
@@ -652,6 +656,12 @@ protected:
   /// the flag of field offset changing due to packed attribute.
   bool HasPackedField;
 
+  /// HandledFirstNonOverlappingEmptyField - An auxiliary field used for AIX.
+  /// When there are OverlappingEmptyFields existing in the aggregate, the
+  /// flag shows if the following first non-empty or empty-but-non-overlapping
+  /// field has been handled, if any.
+  bool HandledFirstNonOverlappingEmptyField;
+
   typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
 
   /// Bases - base classes and their offsets in the record.
@@ -678,17 +688,19 @@ protected:
   ItaniumRecordLayoutBuilder(const ASTContext &Context,
                              EmptySubobjectMap *EmptySubobjects)
       : Context(Context), EmptySubobjects(EmptySubobjects), Size(0),
-        Alignment(CharUnits::One()), UnpackedAlignment(CharUnits::One()),
-        UnadjustedAlignment(CharUnits::One()),
-        UseExternalLayout(false), InferAlignment(false), Packed(false),
-        IsUnion(false), IsMac68kAlign(false), IsMsStruct(false),
-        UnfilledBitsInLastUnit(0), LastBitfieldTypeSize(0),
-        MaxFieldAlignment(CharUnits::Zero()), DataSize(0),
-        NonVirtualSize(CharUnits::Zero()),
+        Alignment(CharUnits::One()), PreferredAlignment(CharUnits::One()),
+        UnpackedAlignment(CharUnits::One()),
+        UnadjustedAlignment(CharUnits::One()), UseExternalLayout(false),
+        InferAlignment(false), Packed(false), IsUnion(false),
+        IsMac68kAlign(false), IsMsStruct(false), UnfilledBitsInLastUnit(0),
+        LastBitfieldTypeSize(0), MaxFieldAlignment(CharUnits::Zero()),
+        DataSize(0), NonVirtualSize(CharUnits::Zero()),
         NonVirtualAlignment(CharUnits::One()),
+        PreferredNVAlignment(CharUnits::One()),
         PaddedFieldSize(CharUnits::Zero()), PrimaryBase(nullptr),
-        PrimaryBaseIsVirtual(false), HasOwnVFPtr(false),
-        HasPackedField(false), FirstNearlyEmptyVBase(nullptr) {}
+        PrimaryBaseIsVirtual(false), HasOwnVFPtr(false), HasPackedField(false),
+        HandledFirstNonOverlappingEmptyField(false),
+        FirstNearlyEmptyVBase(nullptr) {}
 
   void Layout(const RecordDecl *D);
   void Layout(const CXXRecordDecl *D);
@@ -763,9 +775,13 @@ protected:
   /// alignment.
   void FinishLayout(const NamedDecl *D);
 
-  void UpdateAlignment(CharUnits NewAlignment, CharUnits UnpackedNewAlignment);
+  void UpdateAlignment(CharUnits NewAlignment, CharUnits UnpackedNewAlignment,
+                       CharUnits PreferredAlignment);
+  void UpdateAlignment(CharUnits NewAlignment, CharUnits UnpackedNewAlignment) {
+    UpdateAlignment(NewAlignment, UnpackedNewAlignment, NewAlignment);
+  }
   void UpdateAlignment(CharUnits NewAlignment) {
-    UpdateAlignment(NewAlignment, NewAlignment);
+    UpdateAlignment(NewAlignment, NewAlignment, NewAlignment);
   }
 
   /// Retrieve the externally-supplied field offset for the given
@@ -998,7 +1014,7 @@ void ItaniumRecordLayoutBuilder::EnsureVTablePointerAlignment(
   setSize(getSize().alignTo(BaseAlign));
 
   // Update the alignment.
-  UpdateAlignment(BaseAlign, UnpackedBaseAlign);
+  UpdateAlignment(BaseAlign, UnpackedBaseAlign, BaseAlign);
 }
 
 void ItaniumRecordLayoutBuilder::LayoutNonVirtualBases(
@@ -1044,6 +1060,10 @@ void ItaniumRecordLayoutBuilder::LayoutNonVirtualBases(
       Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
     EnsureVTablePointerAlignment(PtrAlign);
     HasOwnVFPtr = true;
+
+    assert(!IsUnion && "Unions cannot be dynamic classes.");
+    HandledFirstNonOverlappingEmptyField = true;
+
     setSize(getSize() + PtrWidth);
     setDataSize(getSize());
   }
@@ -1179,9 +1199,9 @@ void ItaniumRecordLayoutBuilder::LayoutVirtualBase(
 
 CharUnits
 ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
-  const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base->Class);
-
+  assert(!IsUnion && "Unions cannot have base classes.");
 
+  const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base->Class);
   CharUnits Offset;
 
   // Query the external layout to see if it provides an offset.
@@ -1193,45 +1213,77 @@ ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
       HasExternalLayout = External.getExternalNVBaseOffset(Base->Class, Offset);
   }
 
-  // Clang <= 6 incorrectly applied the 'packed' attribute to base classes.
-  // Per GCC's documentation, it only applies to non-static data members.
+  auto getBaseOrPreferredBaseAlignFromUnpacked = [&](CharUnits UnpackedAlign) {
+    // Clang <= 6 incorrectly applied the 'packed' attribute to base classes.
+    // Per GCC's documentation, it only applies to non-static data members.
+    return (Packed && ((Context.getLangOpts().getClangABICompat() <=
+                        LangOptions::ClangABI::Ver6) ||
+                       Context.getTargetInfo().getTriple().isPS4() ||
+                       Context.getTargetInfo().getTriple().isOSAIX()))
+               ? CharUnits::One()
+               : UnpackedAlign;
+  };
+
   CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlignment();
+  CharUnits UnpackedPreferredBaseAlign = Layout.getPreferredNVAlignment();
   CharUnits BaseAlign =
-      (Packed && ((Context.getLangOpts().getClangABICompat() <=
-                   LangOptions::ClangABI::Ver6) ||
-                  Context.getTargetInfo().getTriple().isPS4()))
-          ? CharUnits::One()
-          : UnpackedBaseAlign;
+      getBaseOrPreferredBaseAlignFromUnpacked(UnpackedBaseAlign);
+  CharUnits PreferredBaseAlign =
+      getBaseOrPreferredBaseAlignFromUnpacked(UnpackedPreferredBaseAlign);
+
+  const bool DefaultsToAIXPowerAlignment =
+      Context.getTargetInfo().defaultsToAIXPowerAlignment();
+  if (DefaultsToAIXPowerAlignment) {
+    // AIX `power` alignment does not apply the preferred alignment for
+    // non-union classes if the source of the alignment (the current base in
+    // this context) follows introduction of the first subobject with
+    // exclusively allocated space or zero-extent array.
+    if (!Base->Class->isEmpty() && !HandledFirstNonOverlappingEmptyField) {
+      // By handling a base class that is not empty, we're handling the
+      // "first (inherited) member".
+      HandledFirstNonOverlappingEmptyField = true;
+    } else {
+      UnpackedPreferredBaseAlign = UnpackedBaseAlign;
+      PreferredBaseAlign = BaseAlign;
+    }
+  }
 
+  CharUnits UnpackedAlignTo = !DefaultsToAIXPowerAlignment
+                                  ? UnpackedBaseAlign
+                                  : UnpackedPreferredBaseAlign;
   // If we have an empty base class, try to place it at offset 0.
   if (Base->Class->isEmpty() &&
       (!HasExternalLayout || Offset == CharUnits::Zero()) &&
       EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) {
     setSize(std::max(getSize(), Layout.getSize()));
-    UpdateAlignment(BaseAlign, UnpackedBaseAlign);
+    UpdateAlignment(BaseAlign, UnpackedAlignTo, PreferredBaseAlign);
 
     return CharUnits::Zero();
   }
 
-  // The maximum field alignment overrides base align.
+  // The maximum field alignment overrides the base align/(AIX-only) preferred
+  // base align.
   if (!MaxFieldAlignment.isZero()) {
     BaseAlign = std::min(BaseAlign, MaxFieldAlignment);
-    UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment);
+    PreferredBaseAlign = std::min(PreferredBaseAlign, MaxFieldAlignment);
+    UnpackedAlignTo = std::min(UnpackedAlignTo, MaxFieldAlignment);
   }
 
+  CharUnits AlignTo =
+      !DefaultsToAIXPowerAlignment ? BaseAlign : PreferredBaseAlign;
   if (!HasExternalLayout) {
     // Round up the current record size to the base's alignment boundary.
-    Offset = getDataSize().alignTo(BaseAlign);
+    Offset = getDataSize().alignTo(AlignTo);
 
     // Try to place the base.
     while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset))
-      Offset += BaseAlign;
+      Offset += AlignTo;
   } else {
     bool Allowed = EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset);
     (void)Allowed;
     assert(Allowed && "Base subobject externally placed at overlapping offset");
 
-    if (InferAlignment && Offset < getDataSize().alignTo(BaseAlign)) {
+    if (InferAlignment && Offset < getDataSize().alignTo(AlignTo)) {
       // The externally-supplied base offset is before the base offset we
       // computed. Assume that the structure is packed.
       Alignment = CharUnits::One();
@@ -1248,7 +1300,7 @@ ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
     setSize(std::max(getSize(), Offset + Layout.getSize()));
 
   // Remember max struct/class alignment.
-  UpdateAlignment(BaseAlign, UnpackedBaseAlign);
+  UpdateAlignment(BaseAlign, UnpackedAlignTo, PreferredBaseAlign);
 
   return Offset;
 }
@@ -1260,6 +1312,8 @@ void ItaniumRecordLayoutBuilder::InitializeLayout(const Decl *D) {
   }
 
   Packed = D->hasAttr<PackedAttr>();
+  HandledFirstNonOverlappingEmptyField =
+      !Context.getTargetInfo().defaultsToAIXPowerAlignment();
 
   // Honor the default struct packing maximum alignment flag.
   if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct) {
@@ -1274,6 +1328,7 @@ void ItaniumRecordLayoutBuilder::InitializeLayout(const Decl *D) {
     IsMac68kAlign = true;
     MaxFieldAlignment = CharUnits::fromQuantity(2);
     Alignment = CharUnits::fromQuantity(2);
+    PreferredAlignment = CharUnits::fromQuantity(2);
   } else {
     if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>())
       MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment());
@@ -1293,6 +1348,7 @@ void ItaniumRecordLayoutBuilder::InitializeLayout(const Decl *D) {
       if (UseExternalLayout) {
         if (External.Align > 0) {
           Alignment = Context.toCharUnitsFromBits(External.Align);
+          PreferredAlignment = Context.toCharUnitsFromBits(External.Align);
         } else {
           // The external source didn't have alignment information; infer it.
           InferAlignment = true;
@@ -1321,6 +1377,7 @@ void ItaniumRecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
   NonVirtualSize = Context.toCharUnitsFromBits(
       llvm::alignTo(getSizeInBits(), Context.getTargetInfo().getCharAlign()));
   NonVirtualAlignment = Alignment;
+  PreferredNVAlignment = PreferredAlignment;
 
   // Lay out the virtual bases and add the primary virtual base offsets.
   LayoutVirtualBases(RD, RD);
@@ -1733,25 +1790,46 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
 
 void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
                                              bool InsertExtraPadding) {
+  auto *FieldClass = D->getType()->getAsCXXRecordDecl();
+  bool PotentiallyOverlapping = D->hasAttr<NoUniqueAddressAttr>() && FieldClass;
+  bool IsOverlappingEmptyField =
+      PotentiallyOverlapping && FieldClass->isEmpty();
+
+  CharUnits FieldOffset =
+      (IsUnion || IsOverlappingEmptyField) ? CharUnits::Zero() : getDataSize();
+
+  const bool DefaultsToAIXPowerAlignment =
+      Context.getTargetInfo().defaultsToAIXPowerAlignment();
+  bool FoundFirstNonOverlappingEmptyFieldForAIX = false;
+  if (DefaultsToAIXPowerAlignment && !HandledFirstNonOverlappingEmptyField) {
+    assert(FieldOffset == CharUnits::Zero() &&
+           "The first non-overlapping empty field should have been handled.");
+
+    if (!IsOverlappingEmptyField) {
+      FoundFirstNonOverlappingEmptyFieldForAIX = true;
+
+      // We're going to handle the "first member" based on
+      // `FoundFirstNonOverlappingEmptyFieldForAIX` during the current
+      // invocation of this function; record it as handled for future
+      // invocations (except for unions, because the current field does not
+      // represent all "firsts").
+      HandledFirstNonOverlappingEmptyField = !IsUnion;
+    }
+  }
+
   if (D->isBitField()) {
     LayoutBitField(D);
     return;
   }
 
   uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
-
   // Reset the unfilled bits.
   UnfilledBitsInLastUnit = 0;
   LastBitfieldTypeSize = 0;
 
-  auto *FieldClass = D->getType()->getAsCXXRecordDecl();
-  bool PotentiallyOverlapping = D->hasAttr<NoUniqueAddressAttr>() && FieldClass;
-  bool IsOverlappingEmptyField = PotentiallyOverlapping && FieldClass->isEmpty();
   bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
 
-  CharUnits FieldOffset = (IsUnion || IsOverlappingEmptyField)
-                              ? CharUnits::Zero()
-                              : getDataSize();
+  bool AlignIsRequired = false;
   CharUnits FieldSize;
   CharUnits FieldAlign;
   // The amount of this class's dsize occupied by the field.
@@ -1759,25 +1837,27 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
   // into the field's tail padding.
   CharUnits EffectiveFieldSize;
 
+  auto setDeclInfo = [&](bool IsIncompleteArrayType) {
+    TypeInfo TI = Context.getTypeInfo(D->getType());
+    FieldAlign = Context.toCharUnitsFromBits(TI.Align);
+    // Flexible array members don't have any size, but they have to be
+    // aligned appropriately for their element type.
+    EffectiveFieldSize = FieldSize =
+        IsIncompleteArrayType ? CharUnits::Zero()
+                              : Context.toCharUnitsFromBits(TI.Width);
+    AlignIsRequired = TI.AlignIsRequired;
+  };
+
   if (D->getType()->isIncompleteArrayType()) {
-    // This is a flexible array member; we can't directly
-    // query getTypeInfo about these, so we figure it out here.
-    // Flexible array members don't have any size, but they
-    // have to be aligned appropriately for their element type.
-    EffectiveFieldSize = FieldSize = CharUnits::Zero();
-    const ArrayType* ATy = Context.getAsArrayType(D->getType());
-    FieldAlign = Context.getTypeAlignInChars(ATy->getElementType());
+    setDeclInfo(true /* IsIncompleteArrayType */);
   } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
     unsigned AS = Context.getTargetAddressSpace(RT->getPointeeType());
-    EffectiveFieldSize = FieldSize =
-      Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(AS));
-    FieldAlign =
-      Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(AS));
+    EffectiveFieldSize = FieldSize = Context.toCharUnitsFromBits(
+        Context.getTargetInfo().getPointerWidth(AS));
+    FieldAlign = Context.toCharUnitsFromBits(
+        Context.getTargetInfo().getPointerAlign(AS));
   } else {
-    std::pair<CharUnits, CharUnits> FieldInfo =
-      Context.getTypeInfoInChars(D->getType());
-    EffectiveFieldSize = FieldSize = FieldInfo.first;
-    FieldAlign = FieldInfo.second;
+    setDeclInfo(false /* IsIncompleteArrayType */);
 
     // A potentially-overlapping field occupies its dsize or nvsize, whichever
     // is larger.
@@ -1829,31 +1909,72 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
     }
   }
 
+  // The AIX `power` alignment rules apply the natural alignment of the
+  // "first member" if it is of a floating-point data type (or is an aggregate
+  // whose recursively "first" member or element is such a type). The alignment
+  // associated with these types for subsequent members use an alignment value
+  // where the floating-point data type is considered to have 4-byte alignment.
+  //
+  // For the purposes of the foregoing: vtable pointers, non-empty base classes,
+  // and zero-width bit-fields count as prior members; members of empty class
+  // types marked `no_unique_address` are not considered to be prior members.
+  CharUnits PreferredAlign = FieldAlign;
+  if (DefaultsToAIXPowerAlignment && !AlignIsRequired &&
+      FoundFirstNonOverlappingEmptyFieldForAIX) {
+    auto performBuiltinTypeAlignmentUpgrade = [&](const BuiltinType *BTy) {
+      if (BTy->getKind() == BuiltinType::Double ||
+          BTy->getKind() == BuiltinType::LongDouble) {
+        assert(PreferredAlign == CharUnits::fromQuantity(4) &&
+               "No need to upgrade the alignment value.");
+        PreferredAlign = CharUnits::fromQuantity(8);
+      }
+    };
+
+    const Type *Ty = D->getType()->getBaseElementTypeUnsafe();
+    if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
+      performBuiltinTypeAlignmentUpgrade(CTy->getElementType()->castAs<BuiltinType>());
+    } else if (const BuiltinType *BTy = Ty->getAs<BuiltinType>()) {
+      performBuiltinTypeAlignmentUpgrade(BTy);
+    } else if (const RecordType *RT = Ty->getAs<RecordType>()) {
+      const RecordDecl *RD = RT->getDecl();
+      assert(RD && "Expected non-null RecordDecl.");
+      const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD);
+      PreferredAlign = FieldRecord.getPreferredAlignment();
+    }
+  }
+
   // The align if the field is not packed. This is to check if the attribute
   // was unnecessary (-Wpacked).
-  CharUnits UnpackedFieldAlign = FieldAlign;
+  CharUnits UnpackedFieldAlign =
+      !DefaultsToAIXPowerAlignment ? FieldAlign : PreferredAlign;
   CharUnits UnpackedFieldOffset = FieldOffset;
 
-  if (FieldPacked)
+  if (FieldPacked) {
     FieldAlign = CharUnits::One();
+    PreferredAlign = CharUnits::One();
+  }
   CharUnits MaxAlignmentInChars =
-    Context.toCharUnitsFromBits(D->getMaxAlignment());
+      Context.toCharUnitsFromBits(D->getMaxAlignment());
   FieldAlign = std::max(FieldAlign, MaxAlignmentInChars);
+  PreferredAlign = std::max(PreferredAlign, MaxAlignmentInChars);
   UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars);
 
   // The maximum field alignment overrides the aligned attribute.
   if (!MaxFieldAlignment.isZero()) {
     FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+    PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment);
     UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment);
   }
 
+  CharUnits AlignTo =
+      !DefaultsToAIXPowerAlignment ? FieldAlign : PreferredAlign;
   // Round up the current record size to the field's alignment boundary.
-  FieldOffset = FieldOffset.alignTo(FieldAlign);
+  FieldOffset = FieldOffset.alignTo(AlignTo);
   UnpackedFieldOffset = UnpackedFieldOffset.alignTo(UnpackedFieldAlign);
 
   if (UseExternalLayout) {
     FieldOffset = Context.toCharUnitsFromBits(
-                    updateExternalFieldOffset(D, Context.toBits(FieldOffset)));
+        updateExternalFieldOffset(D, Context.toBits(FieldOffset)));
 
     if (!IsUnion && EmptySubobjects) {
       // Record the fact that we're placing a field at this offset.
@@ -1869,9 +1990,9 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
         // We try offset 0 (for an empty field) and then dsize(C) onwards.
         if (FieldOffset == CharUnits::Zero() &&
             getDataSize() != CharUnits::Zero())
-          FieldOffset = getDataSize().alignTo(FieldAlign);
+          FieldOffset = getDataSize().alignTo(AlignTo);
         else
-          FieldOffset += FieldAlign;
+          FieldOffset += AlignTo;
       }
     }
   }
@@ -1908,9 +2029,9 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
                      (uint64_t)Context.toBits(FieldOffset + FieldSize)));
   }
 
-  // Remember max struct/class alignment.
+  // Remember max struct/class ABI-specified alignment.
   UnadjustedAlignment = std::max(UnadjustedAlignment, FieldAlign);
-  UpdateAlignment(FieldAlign, UnpackedFieldAlign);
+  UpdateAlignment(FieldAlign, UnpackedFieldAlign, PreferredAlign);
 }
 
 void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
@@ -1936,8 +2057,12 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
   uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastUnit;
   uint64_t UnpackedSizeInBits =
       llvm::alignTo(getSizeInBits(), Context.toBits(UnpackedAlignment));
-  uint64_t RoundedSize =
-      llvm::alignTo(getSizeInBits(), Context.toBits(Alignment));
+
+  uint64_t RoundedSize = llvm::alignTo(
+      getSizeInBits(),
+      Context.toBits(!Context.getTargetInfo().defaultsToAIXPowerAlignment()
+                         ? Alignment
+                         : PreferredAlignment));
 
   if (UseExternalLayout) {
     // If we're inferring alignment, and the external size is smaller than
@@ -1945,6 +2070,7 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
     // alignment to 1.
     if (InferAlignment && External.Size < RoundedSize) {
       Alignment = CharUnits::One();
+      PreferredAlignment = CharUnits::One();
       InferAlignment = false;
     }
     setSize(External.Size);
@@ -1981,7 +2107,8 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
 }
 
 void ItaniumRecordLayoutBuilder::UpdateAlignment(
-    CharUnits NewAlignment, CharUnits UnpackedNewAlignment) {
+    CharUnits NewAlignment, CharUnits UnpackedNewAlignment,
+    CharUnits PreferredNewAlignment) {
   // The alignment is not modified when using 'mac68k' alignment or when
   // we have an externally-supplied layout that also provides overall alignment.
   if (IsMac68kAlign || (UseExternalLayout && !InferAlignment))
@@ -1998,6 +2125,12 @@ void ItaniumRecordLayoutBuilder::UpdateAlignment(
            "Alignment not a power of 2");
     UnpackedAlignment = UnpackedNewAlignment;
   }
+
+  if (PreferredNewAlignment > PreferredAlignment) {
+    assert(llvm::isPowerOf2_64(PreferredNewAlignment.getQuantity()) &&
+           "Alignment not a power of 2");
+    PreferredAlignment = PreferredNewAlignment;
+  }
 }
 
 uint64_t
@@ -2009,6 +2142,7 @@ ItaniumRecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field,
     // The externally-supplied field offset is before the field offset we
     // computed. Assume that the structure is packed.
     Alignment = CharUnits::One();
+    PreferredAlignment = CharUnits::One();
     InferAlignment = false;
   }
 
@@ -3063,10 +3197,10 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
       Builder.cxxLayout(RD);
       NewEntry = new (*this) ASTRecordLayout(
           *this, Builder.Size, Builder.Alignment, Builder.Alignment,
-          Builder.RequiredAlignment,
-          Builder.HasOwnVFPtr, Builder.HasOwnVFPtr || Builder.PrimaryBase,
-          Builder.VBPtrOffset, Builder.DataSize, Builder.FieldOffsets,
-          Builder.NonVirtualSize, Builder.Alignment, CharUnits::Zero(),
+          Builder.Alignment, Builder.RequiredAlignment, Builder.HasOwnVFPtr,
+          Builder.HasOwnVFPtr || Builder.PrimaryBase, Builder.VBPtrOffset,
+          Builder.DataSize, Builder.FieldOffsets, Builder.NonVirtualSize,
+          Builder.Alignment, Builder.Alignment, CharUnits::Zero(),
           Builder.PrimaryBase, false, Builder.SharedVBPtrBase,
           Builder.EndsWithZeroSizedObject, Builder.LeadsWithZeroSizedBase,
           Builder.Bases, Builder.VBases);
@@ -3074,8 +3208,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
       Builder.layout(D);
       NewEntry = new (*this) ASTRecordLayout(
           *this, Builder.Size, Builder.Alignment, Builder.Alignment,
-          Builder.RequiredAlignment,
-          Builder.Size, Builder.FieldOffsets);
+          Builder.Alignment, Builder.RequiredAlignment, Builder.Size,
+          Builder.FieldOffsets);
     }
   } else {
     if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
@@ -3095,11 +3229,13 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
       CharUnits NonVirtualSize =
           skipTailPadding ? DataSize : Builder.NonVirtualSize;
       NewEntry = new (*this) ASTRecordLayout(
-          *this, Builder.getSize(), Builder.Alignment, Builder.UnadjustedAlignment,
+          *this, Builder.getSize(), Builder.Alignment,
+          Builder.PreferredAlignment, Builder.UnadjustedAlignment,
           /*RequiredAlignment : used by MS-ABI)*/
           Builder.Alignment, Builder.HasOwnVFPtr, RD->isDynamicClass(),
           CharUnits::fromQuantity(-1), DataSize, Builder.FieldOffsets,
           NonVirtualSize, Builder.NonVirtualAlignment,
+          Builder.PreferredNVAlignment,
           EmptySubobjects.SizeOfLargestEmptySubobject, Builder.PrimaryBase,
           Builder.PrimaryBaseIsVirtual, nullptr, false, false, Builder.Bases,
           Builder.VBases);
@@ -3108,7 +3244,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
       Builder.Layout(D);
 
       NewEntry = new (*this) ASTRecordLayout(
-          *this, Builder.getSize(), Builder.Alignment, Builder.UnadjustedAlignment,
+          *this, Builder.getSize(), Builder.Alignment,
+          Builder.PreferredAlignment, Builder.UnadjustedAlignment,
           /*RequiredAlignment : used by MS-ABI)*/
           Builder.Alignment, Builder.getSize(), Builder.FieldOffsets);
     }
@@ -3260,14 +3397,11 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
   ItaniumRecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/nullptr);
   Builder.Layout(D);
 
-  const ASTRecordLayout *NewEntry =
-    new (*this) ASTRecordLayout(*this, Builder.getSize(),
-                                Builder.Alignment,
-                                Builder.UnadjustedAlignment,
-                                /*RequiredAlignment : used by MS-ABI)*/
-                                Builder.Alignment,
-                                Builder.getDataSize(),
-                                Builder.FieldOffsets);
+  const ASTRecordLayout *NewEntry = new (*this) ASTRecordLayout(
+      *this, Builder.getSize(), Builder.Alignment, Builder.PreferredAlignment,
+      Builder.UnadjustedAlignment,
+      /*RequiredAlignment : used by MS-ABI)*/
+      Builder.Alignment, Builder.getDataSize(), Builder.FieldOffsets);
 
   ObjCLayouts[Key] = NewEntry;
 
@@ -3430,22 +3564,26 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD,
   if (CXXRD && !isMsLayout(C))
     OS << ", dsize=" << Layout.getDataSize().getQuantity();
   OS << ", align=" << Layout.getAlignment().getQuantity();
+  if (C.getTargetInfo().defaultsToAIXPowerAlignment())
+    OS << ", preferredalign=" << Layout.getPreferredAlignment().getQuantity();
 
   if (CXXRD) {
     OS << ",\n";
     PrintIndentNoOffset(OS, IndentLevel - 1);
     OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
     OS << ", nvalign=" << Layout.getNonVirtualAlignment().getQuantity();
+    if (C.getTargetInfo().defaultsToAIXPowerAlignment())
+      OS << ", preferrednvalign="
+         << Layout.getPreferredNVAlignment().getQuantity();
   }
   OS << "]\n";
 }
 
-void ASTContext::DumpRecordLayout(const RecordDecl *RD,
-                                  raw_ostream &OS,
+void ASTContext::DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS,
                                   bool Simple) const {
   if (!Simple) {
     ::DumpRecordLayout(OS, RD, *this, CharUnits(), 0, nullptr,
-                       /*PrintSizeInfo*/true,
+                       /*PrintSizeInfo*/ true,
                        /*IncludeVirtualBases=*/true);
     return;
   }
@@ -3465,9 +3603,13 @@ void ASTContext::DumpRecordLayout(const RecordDecl *RD,
   if (!isMsLayout(*this))
     OS << "  DataSize:" << toBits(Info.getDataSize()) << "\n";
   OS << "  Alignment:" << toBits(Info.getAlignment()) << "\n";
+  if (Target->defaultsToAIXPowerAlignment())
+    OS << "  PreferredAlignment:" << toBits(Info.getPreferredAlignment())
+       << "\n";
   OS << "  FieldOffsets: [";
   for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) {
-    if (i) OS << ", ";
+    if (i)
+      OS << ", ";
     OS << Info.getFieldOffset(i);
   }
   OS << "]>\n";
index cfa362b..7b3acc3 100644 (file)
@@ -719,6 +719,8 @@ public:
   // AIX sets FLT_EVAL_METHOD to be 1.
   unsigned getFloatEvalMethod() const override { return 1; }
   bool hasInt128Type() const override { return false; }
+
+  bool defaultsToAIXPowerAlignment() const override { return true; }
 };
 
 void addWindowsDefines(const llvm::Triple &Triple, const LangOptions &Opts,
index 858059b..ff8579b 100644 (file)
@@ -371,13 +371,16 @@ public:
       PtrDiffType = SignedLong;
       IntPtrType = SignedLong;
       SuitableAlign = 64;
+      LongDoubleWidth = 64;
+      LongDoubleAlign = DoubleAlign = 32;
+      LongDoubleFormat = &llvm::APFloat::IEEEdouble();
       break;
     default:
       break;
     }
 
     if (Triple.isOSFreeBSD() || Triple.isOSNetBSD() || Triple.isOSOpenBSD() ||
-        Triple.getOS() == llvm::Triple::AIX || Triple.isMusl()) {
+        Triple.isMusl()) {
       LongDoubleWidth = LongDoubleAlign = 64;
       LongDoubleFormat = &llvm::APFloat::IEEEdouble();
     }
@@ -406,6 +409,9 @@ public:
       // TODO: Set appropriate ABI for AIX platform.
       resetDataLayout("E-m:a-i64:64-n32:64");
       SuitableAlign = 64;
+      LongDoubleWidth = 64;
+      LongDoubleAlign = DoubleAlign = 32;
+      LongDoubleFormat = &llvm::APFloat::IEEEdouble();
     } else if ((Triple.getArch() == llvm::Triple::ppc64le)) {
       resetDataLayout("e-m:e-i64:64-n32:64");
       ABI = "elfv2";
@@ -414,8 +420,7 @@ public:
       ABI = "elfv1";
     }
 
-    if (Triple.isOSFreeBSD() || Triple.getOS() == llvm::Triple::AIX ||
-        Triple.isMusl()) {
+    if (Triple.isOSFreeBSD() || Triple.isMusl()) {
       LongDoubleWidth = LongDoubleAlign = 64;
       LongDoubleFormat = &llvm::APFloat::IEEEdouble();
     }
diff --git a/clang/test/Layout/aix-Wpacked-expecting-diagnostics.cpp b/clang/test/Layout/aix-Wpacked-expecting-diagnostics.cpp
new file mode 100644 (file)
index 0000000..1980c04
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -Wpacked \
+// RUN:     -fdump-record-layouts -fsyntax-only -verify -x c++ < %s | \
+// RUN:   FileCheck %s
+
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -Wpacked \
+// RUN:     -fdump-record-layouts -fsyntax-only -verify -x c++ < %s | \
+// RUN:   FileCheck %s
+
+struct A {
+  double d;
+};
+
+struct B {
+  char x[8];
+};
+
+struct [[gnu::packed]] C : B, A { // expected-warning{{packed attribute is unnecessary for 'C'}}
+  char x alignas(4)[8];
+};
+
+int b = sizeof(C);
+
+// CHECK:               0 | struct C
+// CHECK-NEXT:          0 |   struct B (base)
+// CHECK-NEXT:          0 |     char [8] x
+// CHECK-NEXT:          8 |   struct A (base)
+// CHECK-NEXT:          8 |     double d
+// CHECK-NEXT:         16 |   char [8] x
+// CHECK-NEXT:            | [sizeof=24, dsize=24, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=24, nvalign=4, preferrednvalign=4]
diff --git a/clang/test/Layout/aix-Wpacked-no-diagnostics.cpp b/clang/test/Layout/aix-Wpacked-no-diagnostics.cpp
new file mode 100644 (file)
index 0000000..ed5362b
--- /dev/null
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -Wpacked \
+// RUN:     -fdump-record-layouts -fsyntax-only -verify -x c++ < %s | \
+// RUN:   FileCheck %s
+
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -Wpacked \
+// RUN:     -fdump-record-layouts -fsyntax-only -verify -x c++ < %s | \
+// RUN:   FileCheck %s
+
+// expected-no-diagnostics
+
+struct [[gnu::packed]] Q {
+  double x [[gnu::aligned(4)]];
+};
+
+struct QQ : Q { char x; };
+
+int a = sizeof(QQ);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct Q
+// CHECK-NEXT:          0 |   double x
+// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=4]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct QQ
+// CHECK-NEXT:          0 |   struct Q (base)
+// CHECK-NEXT:          0 |     double x
+// CHECK-NEXT:          8 |   char x
+// CHECK-NEXT:            | [sizeof=12, dsize=9, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=9, nvalign=4, preferrednvalign=4]
diff --git a/clang/test/Layout/aix-double-struct-member.cpp b/clang/test/Layout/aix-double-struct-member.cpp
new file mode 100644 (file)
index 0000000..b51d104
--- /dev/null
@@ -0,0 +1,428 @@
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \
+// RUN:     -fsyntax-only  %s | \
+// RUN:   FileCheck %s
+
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \
+// RUN:     -fsyntax-only %s | \
+// RUN:   FileCheck %s
+
+namespace test1 {
+// Test the class layout when having a double which is/is not the first struct
+// member.
+struct D {
+  double d1;
+  int i1;
+};
+
+struct DoubleFirst {
+  struct D d2;
+  int i2;
+};
+
+struct IntFirst {
+  int i3;
+  struct D d3;
+};
+
+int a = sizeof(DoubleFirst);
+int b = sizeof(IntFirst);
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:         0 | struct test1::D
+// CHECK-NEXT:         0 |   double d1
+// CHECK-NEXT:         8 |   int i1
+// CHECK-NEXT:           | [sizeof=16, dsize=16, align=4, preferredalign=8,
+// CHECK-NEXT:           |  nvsize=16, nvalign=4, preferrednvalign=8]
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:         0 | struct test1::DoubleFirst
+// CHECK-NEXT:         0 |   struct test1::D d2
+// CHECK-NEXT:         0 |     double d1
+// CHECK-NEXT:         8 |     int i1
+// CHECK-NEXT:        16 |   int i2
+// CHECK-NEXT:           | [sizeof=24, dsize=24, align=4, preferredalign=8,
+// CHECK-NEXT:           |  nvsize=24, nvalign=4, preferrednvalign=8]
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:         0 | struct test1::IntFirst
+// CHECK-NEXT:         0 |   int i3
+// CHECK-NEXT:         4 |   struct test1::D d3
+// CHECK-NEXT:         4 |     double d1
+// CHECK-NEXT:        12 |     int i1
+// CHECK-NEXT:           | [sizeof=20, dsize=20, align=4, preferredalign=4,
+// CHECK-NEXT:           |  nvsize=20, nvalign=4, preferrednvalign=4]
+} // namespace test1
+
+namespace test2 {
+// Test the class layout when having a zero-sized bitfield followed by double.
+struct Double {
+  int : 0;
+  double d;
+};
+
+int a = sizeof(Double);
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:         0 | struct test2::Double
+// CHECK-NEXT:       0:- |   int
+// CHECK-NEXT:         0 |   double d
+// CHECK-NEXT:           | [sizeof=8, dsize=8, align=4, preferredalign=4,
+// CHECK-NEXT:           |  nvsize=8, nvalign=4, preferrednvalign=4]
+} // namespace test2
+
+namespace test3 {
+// Test the class layout when having a double member in union.
+union A {
+  int b;
+  double d;
+};
+
+struct UnionStruct {
+  union A a;
+  int i;
+};
+
+int a = sizeof(UnionStruct);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | union test3::A
+// CHECK-NEXT:          0 |   int b
+// CHECK-NEXT:          0 |   double d
+// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test3::UnionStruct
+// CHECK-NEXT:          0 |   union test3::A a
+// CHECK-NEXT:          0 |     int b
+// CHECK-NEXT:          0 |     double d
+// CHECK-NEXT:          8 |   int i
+// CHECK-NEXT:            | [sizeof=16, dsize=16, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=16, nvalign=4, preferrednvalign=8]
+
+} // namespace test3
+
+namespace test4 {
+// Test the class layout when having multiple base classes.
+struct A {
+  int a;
+};
+
+struct B {
+  double d;
+};
+
+class S : A, B {
+};
+
+int a = sizeof(S);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test4::A
+// CHECK-NEXT:          0 |   int a
+// CHECK-NEXT:            | [sizeof=4, dsize=4, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=4, nvalign=4, preferrednvalign=4]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test4::B
+// CHECK-NEXT:          0 |   double d
+// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | class test4::S
+// CHECK-NEXT:          0 |   struct test4::A (base)
+// CHECK-NEXT:          0 |     int a
+// CHECK-NEXT:          4 |   struct test4::B (base)
+// CHECK-NEXT:          4 |     double d
+// CHECK-NEXT:            | [sizeof=12, dsize=12, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=12, nvalign=4, preferrednvalign=4]
+} // namespace test4
+
+namespace test5 {
+struct Empty {
+};
+
+struct EmptyDer : Empty {
+  double d;
+};
+
+struct NonEmpty {
+  int i;
+};
+
+struct NonEmptyDer : NonEmpty {
+  double d;
+};
+
+int a = sizeof(EmptyDer);
+int b = sizeof(NonEmptyDer);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test5::Empty (empty)
+// CHECK-NEXT:            | [sizeof=1, dsize=1, align=1, preferredalign=1,
+// CHECK-NEXT:            |  nvsize=1, nvalign=1, preferrednvalign=1]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test5::EmptyDer
+// CHECK-NEXT:          0 |   struct test5::Empty (base) (empty)
+// CHECK-NEXT:          0 |   double d
+// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test5::NonEmpty
+// CHECK-NEXT:          0 |   int i
+// CHECK-NEXT:            | [sizeof=4, dsize=4, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=4, nvalign=4, preferrednvalign=4]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test5::NonEmptyDer
+// CHECK-NEXT:          0 |   struct test5::NonEmpty (base)
+// CHECK-NEXT:          0 |     int i
+// CHECK-NEXT:          4 |   double d
+// CHECK-NEXT:            | [sizeof=12, dsize=12, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=12, nvalign=4, preferrednvalign=4]
+} // namespace test5
+
+namespace test6 {
+struct A {
+  struct B {
+    double d[3];
+  } b;
+};
+
+int a = sizeof(A);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test6::A::B
+// CHECK-NEXT:          0 |   double [3] d
+// CHECK-NEXT:            | [sizeof=24, dsize=24, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=24, nvalign=4, preferrednvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test6::A
+// CHECK-NEXT:          0 |   struct test6::A::B b
+// CHECK-NEXT:          0 |     double [3] d
+// CHECK-NEXT:            | [sizeof=24, dsize=24, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=24, nvalign=4, preferrednvalign=8]
+
+} // namespace test6
+
+namespace test7 {
+struct A {
+  struct B {
+    long double _Complex d[3];
+  } b;
+};
+
+int a = sizeof(A);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test7::A::B
+// CHECK-NEXT:          0 |   _Complex long double [3] d
+// CHECK-NEXT:            | [sizeof=48, dsize=48, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=48, nvalign=4, preferrednvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test7::A
+// CHECK-NEXT:          0 |   struct test7::A::B b
+// CHECK-NEXT:          0 |     _Complex long double [3] d
+// CHECK-NEXT:            | [sizeof=48, dsize=48, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=48, nvalign=4, preferrednvalign=8]
+
+} // namespace test7
+
+namespace test8 {
+struct Emp {};
+
+struct Y : Emp {
+  double d;
+};
+
+struct Z : Emp {
+  Y y;
+};
+
+int a = sizeof(Z);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test8::Emp (empty)
+// CHECK-NEXT:            | [sizeof=1, dsize=1, align=1, preferredalign=1,
+// CHECK-NEXT:            |  nvsize=1, nvalign=1, preferrednvalign=1]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test8::Y
+// CHECK-NEXT:          0 |   struct test8::Emp (base) (empty)
+// CHECK-NEXT:          0 |   double d
+// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test8::Z
+// CHECK-NEXT:          0 |   struct test8::Emp (base) (empty)
+// CHECK-NEXT:          8 |   struct test8::Y y
+// CHECK-NEXT:          8 |     struct test8::Emp (base) (empty)
+// CHECK-NEXT:          8 |     double d
+// CHECK-NEXT:            | [sizeof=16, dsize=16, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=16, nvalign=4, preferrednvalign=8]
+
+} // namespace test8
+
+namespace test9 {
+// Test the class layout when having a zero-extent array in a base class, which
+// renders the base class not empty.
+struct A { char zea[0]; };
+
+struct B : A { double d; };
+
+struct C { double d; };
+struct D : A, C { char x; };
+
+int a = sizeof(B);
+int b = sizeof(D);
+
+// CHECK:               0 | struct test9::B
+// CHECK-NEXT:          0 |   struct test9::A (base)
+// CHECK-NEXT:          0 |     char [0] zea
+// CHECK-NEXT:          0 |   double d
+// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=4]
+
+// CHECK:               0 | struct test9::D
+// CHECK-NEXT:          0 |   struct test9::A (base)
+// CHECK-NEXT:          0 |     char [0] zea
+// CHECK-NEXT:          0 |   struct test9::C (base)
+// CHECK-NEXT:          0 |     double d
+// CHECK-NEXT:          8 |   char x
+// CHECK-NEXT:            | [sizeof=12, dsize=9, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=9, nvalign=4, preferrednvalign=4]
+
+} // namespace test9
+
+namespace test10 {
+struct A { double x; };
+struct B : A {};
+
+int a = sizeof(B);
+
+// CHECK:               0 | struct test10::B
+// CHECK-NEXT:          0 |   struct test10::A (base)
+// CHECK-NEXT:          0 |     double x
+// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=8]
+
+} // namespace test10
+
+namespace test11 {
+// Test how #pragma pack and align attribute interacts with AIX `power`
+// alignment rules.
+struct A {
+  char a;
+  double __attribute__((aligned(16))) d;
+  int i;
+};
+
+struct B {
+  double __attribute__((aligned(4))) d1;
+  char a;
+  double d2;
+};
+
+#pragma pack(2)
+struct C {
+  int i;
+  short j;
+  double k;
+};
+
+#pragma pack(2)
+struct D {
+  double d;
+  short j;
+  int i;
+};
+
+#pragma pack(8)
+struct E {
+  double __attribute__((aligned(4))) d;
+  short s;
+};
+
+#pragma pack(4)
+struct F : public D {
+  double d;
+};
+
+#pragma pack(2)
+struct G : public E {
+  int i;
+};
+
+int a = sizeof(A);
+int b = sizeof(B);
+int c = sizeof(C);
+int d = sizeof(D);
+int e = sizeof(E);
+int f = sizeof(F);
+int g = sizeof(G);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test11::A
+// CHECK-NEXT:          0 |   char a
+// CHECK-NEXT:         16 |   double d
+// CHECK-NEXT:         24 |   int i
+// CHECK-NEXT:            | [sizeof=32, dsize=32, align=16, preferredalign=16,
+// CHECK-NEXT:            |  nvsize=32, nvalign=16, preferrednvalign=16]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test11::B
+// CHECK-NEXT:          0 |   double d1
+// CHECK-NEXT:          8 |   char a
+// CHECK-NEXT:         12 |   double d2
+// CHECK-NEXT:            | [sizeof=24, dsize=24, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=24, nvalign=4, preferrednvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test11::C
+// CHECK-NEXT:          0 |   int i
+// CHECK-NEXT:          4 |   short j
+// CHECK-NEXT:          6 |   double k
+// CHECK-NEXT:            | [sizeof=14, dsize=14, align=2, preferredalign=2,
+// CHECK-NEXT:            |  nvsize=14, nvalign=2, preferrednvalign=2]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test11::D
+// CHECK-NEXT:          0 |   double d
+// CHECK-NEXT:          8 |   short j
+// CHECK-NEXT:         10 |   int i
+// CHECK-NEXT:            | [sizeof=14, dsize=14, align=2, preferredalign=2,
+// CHECK-NEXT:            |  nvsize=14, nvalign=2, preferrednvalign=2]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test11::E
+// CHECK-NEXT:          0 |   double d
+// CHECK-NEXT:          8 |   short s
+// CHECK-NEXT:            | [sizeof=16, dsize=16, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=16, nvalign=4, preferrednvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test11::F
+// CHECK-NEXT:          0 |   struct test11::D (base)
+// CHECK-NEXT:          0 |     double d
+// CHECK-NEXT:          8 |     short j
+// CHECK-NEXT:         10 |     int i
+// CHECK-NEXT:         16 |   double d
+// CHECK-NEXT:            | [sizeof=24, dsize=24, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=24, nvalign=4, preferrednvalign=4]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test11::G
+// CHECK-NEXT:          0 |   struct test11::E (base)
+// CHECK-NEXT:          0 |     double d
+// CHECK-NEXT:          8 |     short s
+// CHECK-NEXT:         16 |   int i
+// CHECK-NEXT:            | [sizeof=20, dsize=20, align=2, preferredalign=2,
+// CHECK-NEXT:            |  nvsize=20, nvalign=2, preferrednvalign=2]
+
+} // namespace test11
diff --git a/clang/test/Layout/aix-no-unique-address-with-double.cpp b/clang/test/Layout/aix-no-unique-address-with-double.cpp
new file mode 100644 (file)
index 0000000..5188bf1
--- /dev/null
@@ -0,0 +1,158 @@
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \
+// RUN:     -fsyntax-only %s | \
+// RUN:   FileCheck %s
+
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \
+// RUN:     -fsyntax-only %s | \
+// RUN:   FileCheck %s
+
+struct Empty {};
+
+struct A {
+  double d;
+};
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct Empty (empty)
+// CHECK-NEXT:            | [sizeof=1, dsize=1, align=1, preferredalign=1,
+// CHECK-NEXT:            |  nvsize=1, nvalign=1, preferrednvalign=1]
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct A
+// CHECK-NEXT:          0 |   double d
+// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=8]
+
+struct B {
+  ~B();
+
+  Empty emp;
+  A a;
+  char c;
+};
+
+struct B1 {
+  [[no_unique_address]] B b;
+  char ext[7];
+};
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct B
+// CHECK-NEXT:          0 |   struct Empty emp (empty)
+// CHECK-NEXT:          4 |   struct A a
+// CHECK-NEXT:          4 |     double d
+// CHECK-NEXT:         12 |   char c
+// CHECK-NEXT:            | [sizeof=16, dsize=13, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=13, nvalign=4, preferrednvalign=4]
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct B1
+// CHECK-NEXT:          0 |   struct B b
+// CHECK-NEXT:          0 |     struct Empty emp (empty)
+// CHECK-NEXT:          4 |     struct A a
+// CHECK-NEXT:          4 |       double d
+// CHECK-NEXT:         12 |     char c
+// CHECK-NEXT:         13 |   char [7] ext
+// CHECK-NEXT:            | [sizeof=20, dsize=20, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=20, nvalign=4, preferrednvalign=4]
+
+struct C {
+  ~C();
+
+  [[no_unique_address]] Empty emp;
+  A a;
+  char c;
+};
+
+struct C1 {
+  [[no_unique_address]] C c;
+  char ext[7];
+};
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct C
+// CHECK-NEXT:          0 |   struct Empty emp (empty)
+// CHECK-NEXT:          0 |   struct A a
+// CHECK-NEXT:          0 |     double d
+// CHECK-NEXT:          8 |   char c
+// CHECK-NEXT:            | [sizeof=16, dsize=9, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=9, nvalign=4, preferrednvalign=8]
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct C1
+// CHECK-NEXT:          0 |   struct C c
+// CHECK-NEXT:          0 |     struct Empty emp (empty)
+// CHECK-NEXT:          0 |     struct A a
+// CHECK-NEXT:          0 |       double d
+// CHECK-NEXT:          8 |     char c
+// CHECK-NEXT:          9 |   char [7] ext
+// CHECK-NEXT:            | [sizeof=16, dsize=16, align=4, preferredalign=8,
+// CHECK-NEXT:            |  nvsize=16, nvalign=4, preferrednvalign=8]
+
+struct D {
+  ~D();
+
+  [[no_unique_address]] char notEmp;
+  A a;
+  char c;
+};
+
+struct D1 {
+  [[no_unique_address]] D d;
+  char ext[7];
+};
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct D
+// CHECK-NEXT:          0 |   char notEmp
+// CHECK-NEXT:          4 |   struct A a
+// CHECK-NEXT:          4 |     double d
+// CHECK-NEXT:         12 |   char c
+// CHECK-NEXT:            | [sizeof=16, dsize=13, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=13, nvalign=4, preferrednvalign=4]
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct D1
+// CHECK-NEXT:          0 |   struct D d
+// CHECK-NEXT:          0 |     char notEmp
+// CHECK-NEXT:          4 |     struct A a
+// CHECK-NEXT:          4 |       double d
+// CHECK-NEXT:         12 |     char c
+// CHECK-NEXT:         13 |   char [7] ext
+// CHECK-NEXT:            | [sizeof=20, dsize=20, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=20, nvalign=4, preferrednvalign=4]
+
+struct E {
+  [[no_unique_address]] Empty emp;
+  int : 0;
+  double d;
+};
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct E
+// CHECK-NEXT:          0 |   struct Empty emp (empty)
+// CHECK-NEXT:        0:- |   int
+// CHECK-NEXT:          0 |   double d
+// CHECK-NEXT:            | [sizeof=8, dsize=8, align=4, preferredalign=4,
+// CHECK-NEXT:            |  nvsize=8, nvalign=4, preferrednvalign=4]
+
+struct F {
+  [[no_unique_address]] Empty emp, emp2;
+  double d;
+};
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct F
+// CHECK-NEXT: 0 |   struct Empty emp (empty)
+// CHECK-NEXT: 1 |   struct Empty emp2 (empty)
+// CHECK-NEXT: 0 |   double d
+// CHECK-NEXT:   | [sizeof=8, dsize=8, align=4, preferredalign=8,
+// CHECK-NEXT:   |  nvsize=8, nvalign=4, preferrednvalign=8]
+
+int a = sizeof(Empty);
+int b = sizeof(A);
+int c = sizeof(B1);
+int d = sizeof(C1);
+int e = sizeof(D1);
+int f = sizeof(E);
+int g = sizeof(F);
diff --git a/clang/test/Layout/aix-pack-attr-on-base.cpp b/clang/test/Layout/aix-pack-attr-on-base.cpp
new file mode 100644 (file)
index 0000000..3d0ebab
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -emit-llvm -triple powerpc-ibm-aix-xcoff -x c++ < %s | \
+// RUN:   FileCheck %s
+
+// RUN: %clang_cc1 -emit-llvm -triple powerpc64-ibm-aix-xcoff -x c++ < %s | \
+// RUN:   FileCheck %s
+
+struct A {
+  char x;
+};
+
+struct B {
+  int x;
+};
+
+struct __attribute__((__packed__)) C : A, B {} c;
+
+int s = sizeof(c);
+
+// CHECK: @c = global %struct.C zeroinitializer, align 1
+// CHECK: @s = global i32 5
diff --git a/clang/test/Layout/aix-power-alignment-typedef-2.cpp b/clang/test/Layout/aix-power-alignment-typedef-2.cpp
new file mode 100644 (file)
index 0000000..8e7e3db
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -S -emit-llvm -x c++ < %s | \
+// RUN:   FileCheck %s
+
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -S -emit-llvm -x c++ < %s | \
+// RUN:   FileCheck %s
+
+struct C {
+  double x;
+};
+
+typedef struct C __attribute__((__aligned__(2))) CC;
+
+CC cc;
+
+// CHECK: @cc = global %struct.C zeroinitializer, align 2
diff --git a/clang/test/Layout/aix-power-alignment-typedef.cpp b/clang/test/Layout/aix-power-alignment-typedef.cpp
new file mode 100644 (file)
index 0000000..fc973a1
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts %s | \
+// RUN:   FileCheck %s
+
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts %s | \
+// RUN:   FileCheck %s
+
+namespace test1 {
+typedef double __attribute__((__aligned__(2))) Dbl;
+struct A {
+  Dbl x;
+};
+
+int b = sizeof(A);
+
+// CHECK:          0 | struct test1::A
+// CHECK-NEXT:     0 |   test1::Dbl x
+// CHECK-NEXT:       | [sizeof=8, dsize=8, align=2, preferredalign=2,
+// CHECK-NEXT:       |  nvsize=8, nvalign=2, preferrednvalign=2]
+
+} // namespace test1
+
+namespace test2 {
+typedef double Dbl __attribute__((__aligned__(2)));
+typedef Dbl DblArr[];
+
+union U {
+  DblArr da;
+  char x;
+};
+
+int x = sizeof(U);
+
+// CHECK:          0 | union test2::U
+// CHECK-NEXT:     0 |   test2::DblArr da
+// CHECK-NEXT:     0 |   char x
+// CHECK-NEXT:       | [sizeof=2, dsize=2, align=2, preferredalign=2,
+// CHECK-NEXT:       |  nvsize=2, nvalign=2, preferrednvalign=2]
+
+} // namespace test2
diff --git a/clang/test/Layout/aix-virtual-function-and-base-with-double.cpp b/clang/test/Layout/aix-virtual-function-and-base-with-double.cpp
new file mode 100644 (file)
index 0000000..d3bc441
--- /dev/null
@@ -0,0 +1,112 @@
+// RUN: %clang_cc1 -triple powerpc-ibm-aix-xcoff -fdump-record-layouts \
+// RUN:     -fsyntax-only %s | \
+// RUN:   FileCheck --check-prefixes=CHECK,CHECK32 %s
+
+// RUN: %clang_cc1 -triple powerpc64-ibm-aix-xcoff -fdump-record-layouts \
+// RUN:     -fsyntax-only %s | \
+// RUN:   FileCheck --check-prefixes=CHECK,CHECK64 %s
+
+namespace test1 {
+struct A {
+  double d1;
+  virtual void boo() {}
+};
+
+struct B {
+  double d2;
+  A a;
+};
+
+struct C : public A {
+  double d3;
+};
+
+int i = sizeof(B);
+int j = sizeof(C);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:            0 | struct test1::A
+// CHECK-NEXT:            0 |   (A vtable pointer)
+// CHECK32-NEXT:          4 |   double d1
+// CHECK32-NEXT:            | [sizeof=12, dsize=12, align=4, preferredalign=4,
+// CHECK32-NEXT:            |  nvsize=12, nvalign=4, preferrednvalign=4]
+// CHECK64-NEXT:          8 |   double d1
+// CHECK64-NEXT:            | [sizeof=16, dsize=16, align=8, preferredalign=8,
+// CHECK64-NEXT:            |  nvsize=16, nvalign=8, preferrednvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:            0 | struct test1::B
+// CHECK-NEXT:            0 |   double d2
+// CHECK-NEXT:            8 |   struct test1::A a
+// CHECK-NEXT:            8 |     (A vtable pointer)
+// CHECK32-NEXT:         12 |     double d1
+// CHECK32-NEXT:            | [sizeof=24, dsize=20, align=4, preferredalign=8,
+// CHECK32-NEXT:            |  nvsize=20, nvalign=4, preferrednvalign=8]
+// CHECK64-NEXT:         16 |     double d1
+// CHECK64-NEXT:            | [sizeof=24, dsize=24, align=8, preferredalign=8,
+// CHECK64-NEXT:            |  nvsize=24, nvalign=8, preferrednvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:            0 | struct test1::C
+// CHECK-NEXT:            0 |   struct test1::A (primary base)
+// CHECK-NEXT:            0 |     (A vtable pointer)
+// CHECK32-NEXT:          4 |     double d1
+// CHECK32-NEXT:         12 |   double d3
+// CHECK32-NEXT:            | [sizeof=20, dsize=20, align=4, preferredalign=4,
+// CHECK32-NEXT:            |  nvsize=20, nvalign=4, preferrednvalign=4]
+// CHECK64-NEXT:          8 |     double d1
+// CHECK64-NEXT:         16 |   double d3
+// CHECK64-NEXT:            | [sizeof=24, dsize=24, align=8, preferredalign=8,
+// CHECK64-NEXT:            |  nvsize=24, nvalign=8, preferrednvalign=8]
+
+} // namespace test1
+
+namespace test2 {
+struct A {
+  long long l1;
+};
+
+struct B : public virtual A {
+  double d2;
+};
+
+#pragma pack(2)
+struct C : public virtual A {
+  double __attribute__((aligned(4))) d3;
+};
+
+int i = sizeof(B);
+int j = sizeof(C);
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:            0 | struct test2::A
+// CHECK-NEXT:            0 |   long long l1
+// CHECK-NEXT:              | [sizeof=8, dsize=8, align=8, preferredalign=8,
+// CHECK-NEXT:              |  nvsize=8, nvalign=8, preferrednvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:            0 | struct test2::B
+// CHECK-NEXT:            0 |   (B vtable pointer)
+// CHECK32-NEXT:          4 |   double d2
+// CHECK64-NEXT:          8 |   double d2
+// CHECK-NEXT:           16 |   struct test2::A (virtual base)
+// CHECK-NEXT:           16 |     long long l1
+// CHECK-NEXT:              | [sizeof=24, dsize=24, align=8, preferredalign=8,
+// CHECK32-NEXT:            |  nvsize=12, nvalign=4, preferrednvalign=4]
+// CHECK64-NEXT:            |  nvsize=16, nvalign=8, preferrednvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:            0 | struct test2::C
+// CHECK-NEXT:            0 |   (C vtable pointer)
+// CHECK32-NEXT:          4 |   double d3
+// CHECK32-NEXT:         12 |   struct test2::A (virtual base)
+// CHECK32-NEXT:         12 |     long long l1
+// CHECK32-NEXT:            | [sizeof=20, dsize=20, align=2, preferredalign=2,
+// CHECK32-NEXT:            |  nvsize=12, nvalign=2, preferrednvalign=2]
+// CHECK64-NEXT:          8 |   double d3
+// CHECK64-NEXT:         16 |   struct test2::A (virtual base)
+// CHECK64-NEXT:         16 |     long long l1
+// CHECK64-NEXT:            | [sizeof=24, dsize=24, align=2, preferredalign=2,
+// CHECK64-NEXT:            |  nvsize=16, nvalign=2, preferrednvalign=2]
+
+} // namespace test2