From 6da1098b4b835f312c55cd58cb42ff1cc353efa0 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Thu, 27 May 2010 05:45:51 +0000 Subject: [PATCH] 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! llvm-svn: 104809 --- clang/lib/AST/RecordLayoutBuilder.cpp | 52 ++++++++------ clang/lib/Sema/SemaAttr.cpp | 23 +++++-- clang/test/Parser/pragma-options.c | 2 +- clang/test/Sema/pragma-align-mac68k.c | 98 +++++++++++++++++++++++++++ 4 files changed, 147 insertions(+), 28 deletions(-) create mode 100644 clang/test/Sema/pragma-align-mac68k.c diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index df7ed57a580a..983a2874a735 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -297,7 +297,11 @@ class RecordLayoutBuilder { llvm::SmallVector 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 @@ class RecordLayoutBuilder { /// DataSize - The data size of the record being laid out. uint64_t DataSize; - bool IsUnion; - uint64_t NonVirtualSize; unsigned NonVirtualAlignment; @@ -350,9 +352,10 @@ class RecordLayoutBuilder { 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 @@ class RecordLayoutBuilder { 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 @@ RecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, } } -void RecordLayoutBuilder::InitializeLayout(const RecordDecl *D) { - IsUnion = D->isUnion(); +void RecordLayoutBuilder::InitializeLayout(const Decl *D) { + if (const RecordDecl *RD = dyn_cast(D)) + IsUnion = RD->isUnion(); Packed = D->hasAttr(); - if (const MaxFieldAlignmentAttr *MFAA = D->getAttr()) - 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()) { + IsMac68kAlign = true; + MaxFieldAlignment = 2 * 8; + Alignment = 2 * 8; + } else { + if (const MaxFieldAlignmentAttr *MFAA = D->getAttr()) + MaxFieldAlignment = MFAA->getAlignment(); - if (const AlignedAttr *AA = D->getAttr()) - UpdateAlignment(AA->getMaxAlignment()); + if (const AlignedAttr *AA = D->getAttr()) + UpdateAlignment(AA->getMaxAlignment()); + } } void RecordLayoutBuilder::Layout(const RecordDecl *D) { @@ -1020,13 +1034,7 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { DataSize = Size; } - Packed = D->hasAttr(); - - if (const MaxFieldAlignmentAttr *MFAA = D->getAttr()) - MaxFieldAlignment = MFAA->getAlignment(); - - if (const AlignedAttr *AA = D->getAttr()) - UpdateAlignment(AA->getMaxAlignment()); + InitializeLayout(D); // Layout each ivar sequentially. llvm::SmallVector Ivars; @@ -1239,6 +1247,10 @@ void RecordLayoutBuilder::FinishLayout() { } void RecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { + // The alignment is not modified when using 'mac68k' alignment. + if (IsMac68kAlign) + return; + if (NewAlignment <= Alignment) return; diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 2075f9aa9359..82978c956053 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -25,6 +25,10 @@ using namespace clang; 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 @@ void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) { PragmaPackStack *Stack = static_cast(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 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, 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 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, // 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/clang/test/Parser/pragma-options.c b/clang/test/Parser/pragma-options.c index 815b2b4ead3b..332249fdcfe3 100644 --- a/clang/test/Parser/pragma-options.c +++ b/clang/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/clang/test/Sema/pragma-align-mac68k.c b/clang/test/Sema/pragma-align-mac68k.c new file mode 100644 index 000000000000..d13a0bebb767 --- /dev/null +++ b/clang/test/Sema/pragma-align-mac68k.c @@ -0,0 +1,98 @@ +// RUN: %clang-cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s + +#include + +#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];