Sema: Add initial support for '#pragma options align=mac68k'.
 - Docs are fairly sketchy, if someone wants to pore through gcc to look for
   holes I'd appreciate any failing test cases!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104809 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index df7ed57..983a287 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -297,7 +297,11 @@
   llvm::SmallVector<uint64_t, 16> FieldOffsets;
 
   /// Packed - Whether the record is packed or not.
-  bool Packed;
+  unsigned Packed : 1;
+
+  unsigned IsUnion : 1;
+
+  unsigned IsMac68kAlign : 1;
 
   /// UnfilledBitsInLastByte - If the last field laid out was a bitfield,
   /// this contains the number of bits in the last byte that can be used for
@@ -311,8 +315,6 @@
   /// DataSize - The data size of the record being laid out.
   uint64_t DataSize;
 
-  bool IsUnion;
-
   uint64_t NonVirtualSize;
   unsigned NonVirtualAlignment;
 
@@ -350,9 +352,10 @@
 
   RecordLayoutBuilder(ASTContext &Context, EmptySubobjectMap *EmptySubobjects)
     : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), Alignment(8),
-    Packed(false), UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0),
-    IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8), PrimaryBase(0),
-    PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
+      Packed(false), IsUnion(false), IsMac68kAlign(false),
+      UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0),
+      NonVirtualSize(0), NonVirtualAlignment(8), PrimaryBase(0),
+      PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
 
   void Layout(const RecordDecl *D);
   void Layout(const CXXRecordDecl *D);
@@ -423,7 +426,7 @@
   void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset);
 
   /// InitializeLayout - Initialize record layout for the given record decl.
-  void InitializeLayout(const RecordDecl *D);
+  void InitializeLayout(const Decl *D);
 
   /// FinishLayout - Finalize record layout. Adjust record size based on the
   /// alignment.
@@ -942,16 +945,27 @@
   }
 }
 
-void RecordLayoutBuilder::InitializeLayout(const RecordDecl *D) {
-  IsUnion = D->isUnion();
+void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
+  if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
+    IsUnion = RD->isUnion();
 
   Packed = D->hasAttr<PackedAttr>();
 
-  if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>())
-    MaxFieldAlignment = MFAA->getAlignment();
+  // mac68k alignment supersedes maximum field alignment and attribute aligned,
+  // and forces all structures to have 2-byte alignment. The IBM docs on it
+  // allude to additional (more complicated) semantics, especially with regard
+  // to bit-fields, but gcc appears not to follow that.
+  if (D->hasAttr<AlignMac68kAttr>()) {
+    IsMac68kAlign = true;
+    MaxFieldAlignment = 2 * 8;
+    Alignment = 2 * 8;
+  } else {
+    if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>())
+      MaxFieldAlignment = MFAA->getAlignment();
 
-  if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
-    UpdateAlignment(AA->getMaxAlignment());
+    if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+      UpdateAlignment(AA->getMaxAlignment());
+  }
 }
 
 void RecordLayoutBuilder::Layout(const RecordDecl *D) {
@@ -1020,13 +1034,7 @@
     DataSize = Size;
   }
 
-  Packed = D->hasAttr<PackedAttr>();
-
-  if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>())
-    MaxFieldAlignment = MFAA->getAlignment();
-
-  if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
-    UpdateAlignment(AA->getMaxAlignment());
+  InitializeLayout(D);
 
   // Layout each ivar sequentially.
   llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
@@ -1239,6 +1247,10 @@
 }
 
 void RecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
+  // The alignment is not modified when using 'mac68k' alignment.
+  if (IsMac68kAlign)
+    return;
+
   if (NewAlignment <= Alignment)
     return;
 
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 2075f9a..82978c9 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -25,6 +25,10 @@
 
 namespace {
   struct PackStackEntry {
+    // We just use a sentinel to represent when the stack is set to mac68k
+    // alignment.
+    static const unsigned kMac68kAlignmentSentinel = ~0U;
+
     unsigned Alignment;
     IdentifierInfo *Name;
   };
@@ -102,8 +106,12 @@
   PragmaPackStack *Stack = static_cast<PragmaPackStack*>(PackContext);
 
   // Otherwise, check to see if we need a max field alignment attribute.
-  if (unsigned Alignment = Stack->getAlignment())
-    RD->addAttr(::new (Context) MaxFieldAlignmentAttr(Alignment * 8));
+  if (unsigned Alignment = Stack->getAlignment()) {
+    if (Alignment == PackStackEntry::kMac68kAlignmentSentinel)
+      RD->addAttr(::new (Context) AlignMac68kAttr());
+    else
+      RD->addAttr(::new (Context) MaxFieldAlignmentAttr(Alignment * 8));
+  }
 }
 
 void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
@@ -139,11 +147,9 @@
     if (!PP.getTargetInfo().hasAlignMac68kSupport()) {
       Diag(PragmaLoc, diag::err_pragma_options_align_mac68k_target_unsupported);
       return;
-    } else {
-      // Otherwise, just warn about it for now.
-      Diag(PragmaLoc, diag::warn_pragma_options_align_unsupported_option)
-        << KindLoc;
     }
+    Context->push(0);
+    Context->setAlignment(PackStackEntry::kMac68kAlignmentSentinel);
     break;
 
   default:
@@ -195,7 +201,10 @@
     // FIXME: This should come from the target.
     if (AlignmentVal == 0)
       AlignmentVal = 8;
-    Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal;
+    if (AlignmentVal == PackStackEntry::kMac68kAlignmentSentinel)
+      Diag(PragmaLoc, diag::warn_pragma_pack_show) << "mac68k";
+    else
+      Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal;
     break;
 
   case Action::PPK_Push: // pack(push [, id] [, [n])
diff --git a/test/Parser/pragma-options.c b/test/Parser/pragma-options.c
index 815b2b4..332249f 100644
--- a/test/Parser/pragma-options.c
+++ b/test/Parser/pragma-options.c
@@ -8,5 +8,5 @@
 
 #pragma options align=natural
 #pragma options align=reset
-/* expected-warning {{unsupported alignment option}} */ #pragma options align=mac68k
+#pragma options align=mac68k
 /* expected-warning {{unsupported alignment option}} */ #pragma options align=power
diff --git a/test/Sema/pragma-align-mac68k.c b/test/Sema/pragma-align-mac68k.c
new file mode 100644
index 0000000..d13a0be
--- /dev/null
+++ b/test/Sema/pragma-align-mac68k.c
@@ -0,0 +1,98 @@
+// RUN: %clang-cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+
+#include <stddef.h>
+
+#pragma options align=mac68k
+
+typedef float __attribute__((vector_size (8))) v2f_t;
+typedef float __attribute__((vector_size (16))) v4f_t;
+
+extern int a0_0[__alignof(v2f_t) == 8 ? 1 : -1];
+extern int a0_1[__alignof(v4f_t) == 16 ? 1 : -1];
+
+struct s1 {
+  char f0;
+  int  f1;
+};
+extern int a1_0[offsetof(struct s1, f0) == 0 ? 1 : -1];
+extern int a1_1[offsetof(struct s1, f1) == 2 ? 1 : -1];
+extern int a1_2[sizeof(struct s1) == 6 ? 1 : -1];
+extern int a1_3[__alignof(struct s1) == 2 ? 1 : -1];
+
+struct s2 {
+  char f0;
+  double f1;
+};
+extern int a2_0[offsetof(struct s2, f0) == 0 ? 1 : -1];
+extern int a2_1[offsetof(struct s2, f1) == 2 ? 1 : -1];
+extern int a2_2[sizeof(struct s2) == 10 ? 1 : -1];
+extern int a2_3[__alignof(struct s2) == 2 ? 1 : -1];
+
+struct s3 {
+  char f0;
+  v4f_t f1;
+};
+extern int a3_0[offsetof(struct s3, f0) == 0 ? 1 : -1];
+extern int a3_1[offsetof(struct s3, f1) == 2 ? 1 : -1];
+extern int a3_2[sizeof(struct s3) == 18 ? 1 : -1];
+extern int a3_3[__alignof(struct s3) == 2 ? 1 : -1];
+
+struct s4 {
+  char f0;
+  char f1;
+};
+extern int a4_0[offsetof(struct s4, f0) == 0 ? 1 : -1];
+extern int a4_1[offsetof(struct s4, f1) == 1 ? 1 : -1];
+extern int a4_2[sizeof(struct s4) == 2 ? 1 : -1];
+extern int a4_3[__alignof(struct s4) == 2 ? 1 : -1];
+
+struct s5 {
+  unsigned f0 : 9;
+  unsigned f1 : 9;
+};
+extern int a5_0[sizeof(struct s5) == 4 ? 1 : -1];
+extern int a5_1[__alignof(struct s5) == 2 ? 1 : -1];
+
+struct s6 {
+  unsigned : 0;
+  unsigned : 0;
+};
+extern int a6_0[sizeof(struct s6) == 0 ? 1 : -1];
+extern int a6_1[__alignof(struct s6) == 2 ? 1 : -1];
+
+struct s7 {
+  char : 1;
+  unsigned : 1;
+};
+extern int a7_0[sizeof(struct s7) == 2 ? 1 : -1];
+extern int a7_1[__alignof(struct s7) == 2 ? 1 : -1];
+
+struct s8 {
+  char f0;
+  unsigned : 1;
+};
+extern int a8_0[sizeof(struct s8) == 2 ? 1 : -1];
+extern int a8_1[__alignof(struct s8) == 2 ? 1 : -1];
+
+struct s9 {
+  char f0[3];
+  unsigned : 0;
+  char f1;
+};
+extern int a9_0[sizeof(struct s9) == 6 ? 1 : -1];
+extern int a9_1[__alignof(struct s9) == 2 ? 1 : -1];
+
+struct s10 {
+  char f0;
+};
+extern int a10_0[sizeof(struct s10) == 2 ? 1 : -1];
+extern int a10_1[__alignof(struct s10) == 2 ? 1 : -1];
+
+struct s11 {
+  char f0;
+  v2f_t f1;
+};
+extern int a11_0[offsetof(struct s11, f0) == 0 ? 1 : -1];
+extern int a11_1[offsetof(struct s11, f1) == 2 ? 1 : -1];
+extern int a11_2[sizeof(struct s11) == 10 ? 1 : -1];
+extern int a11_3[__alignof(struct s11) == 2 ? 1 : -1];