Xiangling_L created this revision.
Xiangling_L added reviewers: hubert.reinterpretcast, jasonliu, sfertile, 
cebowleratibm.
Xiangling_L added a project: LLVM.
Herald added subscribers: cfe-commits, kbarton, nemanjai.
Herald added a project: clang.

Implement AIX special alignment rule by recursively checking if the
'real' first member is a double/long double. If yes, then this member
should be naturally aligned to 8 rather than 4.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D79719

Files:
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/AST/RecordLayout.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/AST/RecordLayout.cpp
  clang/lib/AST/RecordLayoutBuilder.cpp
  clang/lib/Basic/Targets/PPC.h
  clang/test/Layout/aix-double-struct-member.cpp
  clang/test/Layout/aix-no-unique-address-with-double.cpp
  clang/test/Layout/aix-virtual-function-and-base-with-double.cpp

Index: clang/test/Layout/aix-virtual-function-and-base-with-double.cpp
===================================================================
--- /dev/null
+++ clang/test/Layout/aix-virtual-function-and-base-with-double.cpp
@@ -0,0 +1,112 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple powerpc-ibm-aix-xcoff \
+// RUN: -fdump-record-layouts -fsyntax-only %s 2>/dev/null | FileCheck \
+// RUN: --check-prefixes=CHECK,CHECK32 %s
+
+// RUN: %clang_cc1 -emit-llvm-only -triple powerpc64-ibm-aix-xcoff \
+// RUN: -fdump-record-layouts -fsyntax-only %s 2>/dev/null | FileCheck \
+// RUN: --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,
+// CHECK32-NEXT:            |  nvsize=12, nvalign=4]
+// CHECK64-NEXT:          8 |   double d1
+// CHECK64-NEXT:            | [sizeof=16, dsize=16, align=8,
+// CHECK64-NEXT:            |  nvsize=16, nvalign=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=8,
+// CHECK32-NEXT:            |  nvsize=20, nvalign=8]
+// CHECK64-NEXT:         16 |     double d1
+// CHECK64-NEXT:            | [sizeof=24, dsize=24, align=8,
+// CHECK64-NEXT:            |  nvsize=24, nvalign=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,
+// CHECK32-NEXT:            |  nvsize=20, nvalign=4]
+// CHECK64-NEXT:          8 |     double d1
+// CHECK64-NEXT:         16 |   double d3
+// CHECK64-NEXT:            | [sizeof=24, dsize=24, align=8,
+// CHECK64-NEXT:            |  nvsize=24, nvalign=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,
+// CHECK-NEXT:              |  nvsize=8, nvalign=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,
+// CHECK32-NEXT:            |  nvsize=12, nvalign=4]
+// CHECK64-NEXT:            |  nvsize=16, nvalign=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,
+// CHECK32-NEXT:            |  nvsize=12, nvalign=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,
+// CHECK64-NEXT:            |  nvsize=16, nvalign=2]
+
+}; // namespace test2
Index: clang/test/Layout/aix-no-unique-address-with-double.cpp
===================================================================
--- /dev/null
+++ clang/test/Layout/aix-no-unique-address-with-double.cpp
@@ -0,0 +1,127 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple powerpc-ibm-aix-xcoff \
+// RUN: -fdump-record-layouts -fsyntax-only %s 2>/dev/null | FileCheck %s
+
+// RUN: %clang_cc1 -emit-llvm-only -triple powerpc64-ibm-aix-xcoff \
+// RUN: -fdump-record-layouts -fsyntax-only %s 2>/dev/null | 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,
+// CHECK-NEXT:            |  nvsize=1, nvalign=1]
+
+// CHECK:     *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct A
+// CHECK-NEXT:          0 |   double d
+// CHECK-NEXT:            | [sizeof=8, dsize=8, align=8,
+// CHECK-NEXT:            |  nvsize=8, nvalign=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,
+// CHECK-NEXT:            |  nvsize=13, nvalign=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,
+// CHECK-NEXT:            |  nvsize=20, nvalign=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=8,
+// CHECK-NEXT:            |  nvsize=9, nvalign=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=8,
+// CHECK-NEXT:            |  nvsize=16, nvalign=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,
+// CHECK-NEXT:            |  nvsize=13, nvalign=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,
+// CHECK-NEXT:            |  nvsize=20, nvalign=4]
+
+int a = sizeof(Empty);
+int b = sizeof(A);
+int c = sizeof(B1);
+int d = sizeof(C1);
+int e = sizeof(D1);
Index: clang/test/Layout/aix-double-struct-member.cpp
===================================================================
--- /dev/null
+++ clang/test/Layout/aix-double-struct-member.cpp
@@ -0,0 +1,295 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple powerpc-ibm-aix-xcoff \
+// RUN: -fdump-record-layouts -fsyntax-only %s 2>/dev/null | FileCheck %s
+
+// RUN: %clang_cc1 -emit-llvm-only -triple powerpc64-ibm-aix-xcoff \
+// RUN: -fdump-record-layouts -fsyntax-only %s 2>/dev/null | FileCheck %s
+
+namespace test1 {
+// Test double alignment when it 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=8,
+// CHECK-NEXT:           |  nvsize=16, nvalign=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=8,
+// CHECK-NEXT:           |  nvsize=24, nvalign=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,
+// CHECK-NEXT:           |  nvsize=20, nvalign=4]
+}; // namespace test1
+
+namespace test2 {
+// Test AIX layout for 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,
+// CHECK-NEXT:           |  nvsize=8, nvalign=4]
+}; // namespace test2
+
+namespace test3 {
+// Test the alignment of 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=8,
+// CHECK-NEXT:            |  nvsize=8, nvalign=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=8,
+// CHECK-NEXT:            |  nvsize=16, nvalign=8]
+}; // namespace test3
+
+namespace test4 {
+// Test the AIX Alignment rule when layout base class.
+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,
+// CHECK-NEXT:            |  nvsize=4, nvalign=4]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test4::B
+// CHECK-NEXT:          0 |   double d
+// CHECK-NEXT:            | [sizeof=8, dsize=8, align=8,
+// CHECK-NEXT:            |  nvsize=8, nvalign=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,
+// CHECK-NEXT:            |  nvsize=12, nvalign=4]
+}; // namespace test4
+
+namespace test5 {
+// Test the AIX alignment rule with basic inheritance.
+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,
+// CHECK-NEXT:            |  nvsize=1, nvalign=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=8,
+// CHECK-NEXT:            |  nvsize=8, nvalign=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,
+// CHECK-NEXT:            |  nvsize=4, nvalign=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,
+// CHECK-NEXT:            |  nvsize=12, nvalign=4]
+}; // namespace test5
+
+namespace test6 {
+// Test how #pragma pack and align attribute interacts with AIX alignment.
+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 test6::A
+// CHECK-NEXT:          0 |   char a
+// CHECK-NEXT:         16 |   double d
+// CHECK-NEXT:         24 |   int i
+// CHECK-NEXT:            | [sizeof=32, dsize=32, align=16,
+// CHECK-NEXT:            |  nvsize=32, nvalign=16]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test6::B
+// CHECK-NEXT:          0 |   double d1
+// CHECK-NEXT:          8 |   char a
+// CHECK-NEXT:         12 |   double d2
+// CHECK-NEXT:            | [sizeof=24, dsize=24, align=8,
+// CHECK-NEXT:            |  nvsize=24, nvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test6::C
+// CHECK-NEXT:          0 |   int i
+// CHECK-NEXT:          4 |   short j
+// CHECK-NEXT:          6 |   double k
+// CHECK-NEXT:            | [sizeof=14, dsize=14, align=2,
+// CHECK-NEXT:            |  nvsize=14, nvalign=2]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test6::D
+// CHECK-NEXT:          0 |   double d
+// CHECK-NEXT:          8 |   short j
+// CHECK-NEXT:         10 |   int i
+// CHECK-NEXT:            | [sizeof=14, dsize=14, align=2,
+// CHECK-NEXT:            |  nvsize=14, nvalign=2]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test6::E
+// CHECK-NEXT:          0 |   double d
+// CHECK-NEXT:          8 |   short s
+// CHECK-NEXT:            | [sizeof=16, dsize=16, align=8,
+// CHECK-NEXT:            |  nvsize=16, nvalign=8]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test6::F
+// CHECK-NEXT:          0 |   struct test6::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,
+// CHECK-NEXT:            |  nvsize=24, nvalign=4]
+
+// CHECK:      *** Dumping AST Record Layout
+// CHECK-NEXT:          0 | struct test6::G
+// CHECK-NEXT:          0 |   struct test6::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,
+// CHECK-NEXT:            |  nvsize=20, nvalign=2]
+
+}; // namespace test6
Index: clang/lib/Basic/Targets/PPC.h
===================================================================
--- clang/lib/Basic/Targets/PPC.h
+++ clang/lib/Basic/Targets/PPC.h
@@ -361,11 +361,17 @@
     }
 
     if (Triple.isOSFreeBSD() || Triple.isOSNetBSD() || Triple.isOSOpenBSD() ||
-        Triple.getOS() == llvm::Triple::AIX || Triple.isMusl()) {
+        Triple.isMusl()) {
       LongDoubleWidth = LongDoubleAlign = 64;
       LongDoubleFormat = &llvm::APFloat::IEEEdouble();
     }
 
+    if (Triple.isOSAIX()) {
+      LongDoubleWidth = 64;
+      LongDoubleAlign = DoubleAlign = 32;
+      LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+    }
+
     // PPC32 supports atomics up to 4 bytes.
     MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
   }
@@ -397,12 +403,17 @@
     if (Triple.getOS() == llvm::Triple::AIX)
       SuitableAlign = 64;
 
-    if (Triple.isOSFreeBSD() || Triple.getOS() == llvm::Triple::AIX ||
-        Triple.isMusl()) {
+    if (Triple.isOSFreeBSD() || Triple.isMusl()) {
       LongDoubleWidth = LongDoubleAlign = 64;
       LongDoubleFormat = &llvm::APFloat::IEEEdouble();
     }
 
+    if (Triple.isOSAIX()) {
+      LongDoubleWidth = 64;
+      LongDoubleAlign = DoubleAlign = 32;
+      LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+    }
+
     // PPC64 supports atomics up to 8 bytes.
     MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
   }
Index: clang/lib/AST/RecordLayoutBuilder.cpp
===================================================================
--- clang/lib/AST/RecordLayoutBuilder.cpp
+++ clang/lib/AST/RecordLayoutBuilder.cpp
@@ -6,7 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/AST/RecordLayout.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTDiagnostic.h"
 #include "clang/AST/Attr.h"
@@ -15,6 +14,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/RecordLayout.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/Support/Format.h"
@@ -806,6 +806,10 @@
 };
 } // end anonymous namespace
 
+static bool isAIXLayout(const ASTContext &Context) {
+  return Context.getTargetInfo().getTriple().getOS() == llvm::Triple::AIX;
+}
+
 void ItaniumRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
   for (const auto &I : RD->bases()) {
     assert(!I.getType()->isDependentType() &&
@@ -1936,8 +1940,23 @@
   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 AlignValue = Context.toBits(Alignment);
+  if (isAIXLayout(Context))
+    if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
+      if (Context.shouldCheckRecordFirstMember(Alignment, MaxFieldAlignment))
+        // AIX ABI has this special rule that in aggregates, the first member of
+        // floating point data type(or aggregate type contains floating point
+        // data type) is aligned according to its natural alignment value,
+        // subsequent of such data type members of the aggregate are aligned on
+        // 4-byte boundaries.
+        AlignValue =
+            Context.hasFloatingPointAsFirstMember(RD, MaxFieldAlignment)
+                ? Context.toBits(CharUnits::fromQuantity(8))
+                : AlignValue;
+    }
+
+  uint64_t RoundedSize = llvm::alignTo(getSizeInBits(), AlignValue);
 
   if (UseExternalLayout) {
     // If we're inferring alignment, and the external size is smaller than
@@ -3047,20 +3066,19 @@
     if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
       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.PrimaryBase, false, Builder.SharedVBPtrBase,
-          Builder.EndsWithZeroSizedObject, Builder.LeadsWithZeroSizedBase,
-          Builder.Bases, Builder.VBases);
+          *this, Builder.Size, Builder.Alignment, Builder.MaxFieldAlignment,
+          Builder.Alignment, Builder.RequiredAlignment, Builder.HasOwnVFPtr,
+          Builder.HasOwnVFPtr || Builder.PrimaryBase, Builder.VBPtrOffset,
+          Builder.DataSize, Builder.FieldOffsets, Builder.NonVirtualSize,
+          Builder.Alignment, CharUnits::Zero(), Builder.PrimaryBase, false,
+          Builder.SharedVBPtrBase, Builder.EndsWithZeroSizedObject,
+          Builder.LeadsWithZeroSizedBase, Builder.Bases, Builder.VBases);
     } else {
       Builder.layout(D);
       NewEntry = new (*this) ASTRecordLayout(
-          *this, Builder.Size, Builder.Alignment, Builder.Alignment,
-          Builder.RequiredAlignment,
-          Builder.Size, Builder.FieldOffsets);
+          *this, Builder.Size, Builder.Alignment, Builder.MaxFieldAlignment,
+          Builder.Alignment, Builder.RequiredAlignment, Builder.Size,
+          Builder.FieldOffsets);
     }
   } else {
     if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
@@ -3079,8 +3097,9 @@
           skipTailPadding ? Builder.getSize() : Builder.getDataSize();
       CharUnits NonVirtualSize =
           skipTailPadding ? DataSize : Builder.NonVirtualSize;
-      NewEntry = new (*this) ASTRecordLayout(
-          *this, Builder.getSize(), Builder.Alignment, Builder.UnadjustedAlignment,
+        NewEntry = new (*this) ASTRecordLayout(
+          *this, Builder.getSize(), Builder.Alignment,
+          Builder.MaxFieldAlignment, Builder.UnadjustedAlignment,
           /*RequiredAlignment : used by MS-ABI)*/
           Builder.Alignment, Builder.HasOwnVFPtr, RD->isDynamicClass(),
           CharUnits::fromQuantity(-1), DataSize, Builder.FieldOffsets,
@@ -3093,7 +3112,8 @@
       Builder.Layout(D);
 
       NewEntry = new (*this) ASTRecordLayout(
-          *this, Builder.getSize(), Builder.Alignment, Builder.UnadjustedAlignment,
+          *this, Builder.getSize(), Builder.Alignment,
+          Builder.MaxFieldAlignment, Builder.UnadjustedAlignment,
           /*RequiredAlignment : used by MS-ABI)*/
           Builder.Alignment, Builder.getSize(), Builder.FieldOffsets);
     }
@@ -3245,14 +3265,11 @@
   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.MaxFieldAlignment,
+      Builder.UnadjustedAlignment,
+      /*RequiredAlignment : used by MS-ABI)*/
+      Builder.Alignment, Builder.getDataSize(), Builder.FieldOffsets);
 
   ObjCLayouts[Key] = NewEntry;
 
@@ -3414,23 +3431,33 @@
   OS << "[sizeof=" << Layout.getSize().getQuantity();
   if (CXXRD && !isMsLayout(C))
     OS << ", dsize=" << Layout.getDataSize().getQuantity();
-  OS << ", align=" << Layout.getAlignment().getQuantity();
+  OS << ", align="
+     << (!isAIXLayout(C) ? Layout.getAlignment().getQuantity()
+                         : C.toCharUnitsFromBits(
+                                C.getPreferredTypeAlign(RD->getTypeForDecl()))
+                               .getQuantity());
 
   if (CXXRD) {
     OS << ",\n";
     PrintIndentNoOffset(OS, IndentLevel - 1);
     OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
-    OS << ", nvalign=" << Layout.getNonVirtualAlignment().getQuantity();
+
+    CharUnits nvalign = Layout.getNonVirtualAlignment();
+    CharUnits MaxFieldAlignment = Layout.getMaxFieldAlignment();
+    if (isAIXLayout(C) &&
+        C.shouldCheckRecordFirstMember(nvalign, MaxFieldAlignment))
+      if (C.hasFloatingPointAsFirstMember(RD, MaxFieldAlignment))
+        nvalign = CharUnits::fromQuantity(8);
+    OS << ", nvalign=" << nvalign.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;
   }
@@ -3449,10 +3476,14 @@
   OS << "  Size:" << toBits(Info.getSize()) << "\n";
   if (!isMsLayout(*this))
     OS << "  DataSize:" << toBits(Info.getDataSize()) << "\n";
-  OS << "  Alignment:" << toBits(Info.getAlignment()) << "\n";
+  OS << "  Alignment:"
+     << (!isAIXLayout(*this) ? toBits(Info.getAlignment())
+                             : getPreferredTypeAlign(RD->getTypeForDecl()))
+     << "\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: clang/lib/AST/RecordLayout.cpp
===================================================================
--- clang/lib/AST/RecordLayout.cpp
+++ clang/lib/AST/RecordLayout.cpp
@@ -29,39 +29,34 @@
 
 ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size,
                                  CharUnits alignment,
+                                 CharUnits maxFieldAlignment,
                                  CharUnits unadjustedAlignment,
                                  CharUnits requiredAlignment,
                                  CharUnits datasize,
                                  ArrayRef<uint64_t> fieldoffsets)
     : Size(size), DataSize(datasize), Alignment(alignment),
+      MaxFieldAlignment(maxFieldAlignment),
       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 maxFieldAlignment, 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),
+      MaxFieldAlignment(maxFieldAlignment),
+      UnadjustedAlignment(unadjustedAlignment),
+      RequiredAlignment(requiredAlignment),
+      CXXInfo(new (Ctx) CXXRecordLayoutInfo) {
   FieldOffsets.append(Ctx, fieldoffsets.begin(), fieldoffsets.end());
 
   CXXInfo->PrimaryBase.setPointer(PrimaryBase);
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -2368,6 +2368,127 @@
   return toCharUnitsFromBits(getTypeUnadjustedAlign(T));
 }
 
+bool ASTContext::shouldCheckRecordFirstMember(
+    CharUnits Alignment, CharUnits MaxFieldAligment) const {
+  if (Alignment != CharUnits::fromQuantity(4))
+    // On AIX, the object which does not have 4-byte alignment is guaranteed to
+    // be aligned to the preferred alignement value.
+    return false;
+
+  if (!MaxFieldAligment.isZero() &&
+      MaxFieldAligment <= CharUnits::fromQuantity(4))
+    // #pragma pack(n) will not affect the preferred alignment on AIX if n is
+    // no more than 4.
+    return false;
+
+  return true;
+}
+
+/// hasFloatingPointAsFirstMember - For Itanium ABI, check if a RecordDecl has a
+/// double or a long double as its first field.
+bool ASTContext::hasFloatingPointAsFirstMember(
+    const RecordDecl *RD, const CharUnits MaxFieldAlignment) const {
+  auto CXXRD = dyn_cast<CXXRecordDecl>(RD);
+
+  if (CXXRD) {
+    // Check if the RecordDecl has a Vtable pointer as the first member.
+    if (CXXRD->isDynamicClass()) {
+      return false;
+    }
+
+    // Get the first non-empty non-virtual base class if any.
+    CXXRecordDecl *Base = nullptr;
+    for (const CXXBaseSpecifier &B : CXXRD->bases()) {
+      CXXRecordDecl *Tmp = B.getType()->getAsCXXRecordDecl();
+      if (!Tmp->isEmpty() && !B.isVirtual()) {
+        Base = Tmp;
+        break;
+      }
+    }
+
+    if (Base != nullptr) {
+      const ASTRecordLayout &Layout = getASTRecordLayout(Base);
+      return hasFloatingPointAsFirstMember(Base, Layout.getMaxFieldAlignment());
+    }
+  }
+
+  if (RD->isUnion()) {
+    // On AIX, double/long double should be always naturally aligned to 8 in a
+    // Union.
+    bool flag = false;
+    for (RecordDecl::field_iterator FI = RD->field_begin(), E = RD->field_end();
+         FI != E; ++FI) {
+      const FieldDecl *Field = *FI;
+      if (const BuiltinType *BTy =
+              getBaseElementType(Field->getType())->getAs<BuiltinType>()) {
+        if (BTy->isSpecificBuiltinType(BuiltinType::LongDouble) ||
+            BTy->isSpecificBuiltinType(BuiltinType::Double))
+          flag = flag || true;
+      } else if (auto RT = Field->getType()->getAs<RecordType>()) {
+        // Recursively check fields of a record type.
+        const RecordDecl *RD = RT->getDecl();
+        const ASTRecordLayout &Layout = getASTRecordLayout(RD);
+        flag = flag ||
+               hasFloatingPointAsFirstMember(RD, Layout.getMaxFieldAlignment());
+      }
+
+      if (flag) {
+        // We verified that the first member is a double/long double.
+        if ((MaxFieldAlignment.isZero() ||
+             MaxFieldAlignment >= CharUnits::fromQuantity(8)) &&
+            toCharUnitsFromBits(Field->getMaxAlignment()) <=
+                CharUnits::fromQuantity(4))
+          return true;
+
+        return false;
+      }
+    }
+    return false;
+  }
+
+  // Check the real first field.
+  const FieldDecl *Field = nullptr;
+  for (RecordDecl::field_iterator FI = RD->field_begin(), E = RD->field_end();
+       FI != E; ++FI) {
+    const FieldDecl *D = *FI;
+    auto *FieldClass = D->getType()->getAsCXXRecordDecl();
+    bool PotentiallyOverlapping =
+        D->hasAttr<NoUniqueAddressAttr>() && FieldClass;
+    if (PotentiallyOverlapping && FieldClass->isEmpty()) {
+      // An empty CXXRecordDecl with [[no_unique_address]] attribute will not
+      // affect the double/long double alignment.
+      continue;
+    }
+    Field = D;
+    break;
+  }
+
+  if (Field == nullptr)
+    return false;
+
+  if (const BuiltinType *BTy =
+          getBaseElementType(Field->getType())->getAs<BuiltinType>()) {
+    if (BTy->isSpecificBuiltinType(BuiltinType::LongDouble) ||
+        BTy->isSpecificBuiltinType(BuiltinType::Double))
+      if ((MaxFieldAlignment.isZero() ||
+           MaxFieldAlignment >= CharUnits::fromQuantity(8)) &&
+          toCharUnitsFromBits(Field->getMaxAlignment()) <=
+              CharUnits::fromQuantity(4))
+        return true;
+
+    return false;
+  }
+
+  // Recursively check fields of record type.
+  if (auto RT = Field->getType()->getAs<RecordType>()) {
+    const RecordDecl *RD = RT->getDecl();
+    const ASTRecordLayout &Layout = getASTRecordLayout(RD);
+    return hasFloatingPointAsFirstMember(RD, Layout.getMaxFieldAlignment());
+  }
+
+  return false;
+}
+
 /// 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
@@ -2392,12 +2513,25 @@
     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) &&
+       getTargetInfo().getTriple().isOSAIX()))
     // Don't increase the alignment if an alignment attribute was specified on a
     // typedef declaration.
     if (!TI.AlignIsRequired)
       return std::max(ABIAlign, (unsigned)getTypeSize(T));
 
+  if (const auto *RT = T->getAs<RecordType>())
+    // On AIX, upgrade the preferred alignment value if thie Record has a double
+    // as its first member.
+    if (getTargetInfo().getTriple().isOSAIX()) {
+      const RecordDecl *RD = RT->getDecl();
+      const ASTRecordLayout &Layout = getASTRecordLayout(RD);
+      CharUnits MaxFieldAlignment = Layout.MaxFieldAlignment;
+      if (shouldCheckRecordFirstMember(Layout.Alignment, MaxFieldAlignment) &&
+          hasFloatingPointAsFirstMember(RD, MaxFieldAlignment))
+        return std::max(ABIAlign, (unsigned)toBits(CharUnits::fromQuantity(8)));
+    }
   return ABIAlign;
 }
 
Index: clang/include/clang/AST/RecordLayout.h
===================================================================
--- clang/include/clang/AST/RecordLayout.h
+++ clang/include/clang/AST/RecordLayout.h
@@ -70,6 +70,9 @@
   // Alignment - Alignment of record in characters.
   CharUnits Alignment;
 
+  /// The maximum allowed field alignment. This is set by #pragma pack.
+  CharUnits MaxFieldAlignment;
+
   // UnadjustedAlignment - Maximum of the alignments of the record members in
   // characters.
   CharUnits UnadjustedAlignment;
@@ -139,30 +142,25 @@
   CXXRecordLayoutInfo *CXXInfo = nullptr;
 
   ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
-                  CharUnits unadjustedAlignment,
+                  CharUnits maxFieldAlignment, 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 maxFieldAlignment, 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 *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 +173,10 @@
   /// getAlignment - Get the record alignment in characters.
   CharUnits getAlignment() const { return Alignment; }
 
+  /// getMaxFieldAlignment - Get the maximum allowed field alignment. This is
+  /// set by #pragma pack.
+  CharUnits getMaxFieldAlignment() const { return MaxFieldAlignment; }
+
   /// getUnadjustedAlignment - Get the record alignment in characters, before
   /// alignment adjustement.
   CharUnits getUnadjustedAlignment() const { return UnadjustedAlignment; }
@@ -193,9 +195,7 @@
 
   /// 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.
@@ -287,9 +287,7 @@
     return !CXXInfo->VBPtrOffset.isNegative();
   }
 
-  CharUnits getRequiredAlignment() const {
-    return RequiredAlignment;
-  }
+  CharUnits getRequiredAlignment() const { return RequiredAlignment; }
 
   bool endsWithZeroSizedObject() const {
     return CXXInfo && CXXInfo->EndsWithZeroSizedObject;
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -2111,6 +2111,14 @@
   bool isAlignmentRequired(const Type *T) const;
   bool isAlignmentRequired(QualType T) const;
 
+  bool shouldCheckRecordFirstMember(CharUnits Alignment,
+                                    CharUnits MaxFieldAligment) const;
+
+  /// hasFloatingPointAsFirstMember - Check if a RecordDecl has a double or a
+  /// long double as its first field.
+  bool hasFloatingPointAsFirstMember(const RecordDecl *RD,
+                                     const CharUnits MaxFieldAlignment) const;
+
   /// Return the "preferred" alignment of the specified type \p T for
   /// the current target, in bits.
   ///
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to