Index: cfe/trunk/lib/AST/RecordLayoutBuilder.cpp =================================================================== --- cfe/trunk/lib/AST/RecordLayoutBuilder.cpp +++ cfe/trunk/lib/AST/RecordLayoutBuilder.cpp @@ -1552,7 +1552,8 @@ FieldAlign = 1; // But, if there's an 'aligned' attribute on the field, honor that. - if (unsigned ExplicitFieldAlign = D->getMaxAlignment()) { + unsigned ExplicitFieldAlign = D->getMaxAlignment(); + if (ExplicitFieldAlign) { FieldAlign = std::max(FieldAlign, ExplicitFieldAlign); UnpackedFieldAlign = std::max(UnpackedFieldAlign, ExplicitFieldAlign); } @@ -1601,6 +1602,10 @@ (AllowPadding && (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)) { FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign); + } else if (ExplicitFieldAlign) { + // TODO: figure it out what needs to be done on targets that don't honor + // bit-field type alignment like ARM APCS ABI. + FieldOffset = llvm::RoundUpToAlignment(FieldOffset, ExplicitFieldAlign); } // Repeat the computation for diagnostic purposes. @@ -1609,6 +1614,9 @@ (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize)) UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset, UnpackedFieldAlign); + else if (ExplicitFieldAlign) + UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset, + ExplicitFieldAlign); } // If we're using external layout, give the external layout a chance Index: cfe/trunk/test/Sema/bitfield-layout.c =================================================================== --- cfe/trunk/test/Sema/bitfield-layout.c +++ cfe/trunk/test/Sema/bitfield-layout.c @@ -1,13 +1,25 @@ // RUN: %clang_cc1 %s -fsyntax-only -verify -triple=i686-apple-darwin9 +// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=arm-linux-gnueabihf +// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=aarch64-linux-gnu // expected-no-diagnostics +#include -#define CHECK_SIZE(kind, name, size) extern int name##1[sizeof(kind name) == size ? 1 : -1]; -#define CHECK_ALIGN(kind, name, size) extern int name##2[__alignof(kind name) == size ? 1 : -1]; +#define CHECK_SIZE(kind, name, size) \ + extern int name##_1[sizeof(kind name) == size ? 1 : -1]; +#define CHECK_ALIGN(kind, name, size) \ + extern int name##_2[__alignof(kind name) == size ? 1 : -1]; +#define CHECK_OFFSET(kind, name, member, offset) \ + extern int name##_3[offsetof(kind name, member) == offset ? 1 : -1]; // Zero-width bit-fields struct a {char x; int : 0; char y;}; +#if defined(__arm__) || defined(__aarch64__) +CHECK_SIZE(struct, a, 8) +CHECK_ALIGN(struct, a, 4) +#else CHECK_SIZE(struct, a, 5) CHECK_ALIGN(struct, a, 1) +#endif // Zero-width bit-fields with packed struct __attribute__((packed)) a2 { short x : 9; char : 0; int y : 17; }; @@ -16,8 +28,13 @@ // Zero-width bit-fields at the end of packed struct struct __attribute__((packed)) a3 { short x : 9; int : 0; }; +#if defined(__arm__) || defined(__aarch64__) +CHECK_SIZE(struct, a3, 4) +CHECK_ALIGN(struct, a3, 4) +#else CHECK_SIZE(struct, a3, 4) CHECK_ALIGN(struct, a3, 1) +#endif // For comparison, non-zero-width bit-fields at the end of packed struct struct __attribute__((packed)) a4 { short x : 9; int : 1; }; @@ -25,17 +42,32 @@ CHECK_ALIGN(struct, a4, 1) union b {char x; int : 0; char y;}; +#if defined(__arm__) || defined(__aarch64__) +CHECK_SIZE(union, b, 4) +CHECK_ALIGN(union, b, 4) +#else CHECK_SIZE(union, b, 1) CHECK_ALIGN(union, b, 1) +#endif // Unnamed bit-field align struct c {char x; int : 20;}; +#if defined(__arm__) || defined(__aarch64__) +CHECK_SIZE(struct, c, 4) +CHECK_ALIGN(struct, c, 4) +#else CHECK_SIZE(struct, c, 4) CHECK_ALIGN(struct, c, 1) +#endif union d {char x; int : 20;}; +#if defined(__arm__) || defined(__aarch64__) +CHECK_SIZE(union, d, 4) +CHECK_ALIGN(union, d, 4) +#else CHECK_SIZE(union, d, 3) CHECK_ALIGN(union, d, 1) +#endif // Bit-field packing struct __attribute__((packed)) e {int x : 4, y : 30, z : 30;}; @@ -56,3 +88,153 @@ CHECK_SIZE(struct, s0, 0x32100008) CHECK_ALIGN(struct, s0, 4) +// Bit-field with explicit align bigger than normal. +struct g0 { + char a; + __attribute__((aligned(16))) int b : 1; + char c; +}; + +CHECK_SIZE(struct, g0, 32); +CHECK_ALIGN(struct, g0, 16); +CHECK_OFFSET(struct, g0, c, 17); + +// Bit-field with explicit align smaller than normal. +struct g1 { + char a; + __attribute__((aligned(2))) int b : 1; + char c; +}; + +CHECK_SIZE(struct, g1, 4); +CHECK_ALIGN(struct, g1, 4); +CHECK_OFFSET(struct, g1, c, 3); + +// Same as above but without explicit align. +struct g2 { + char a; + int b : 1; + char c; +}; + +CHECK_SIZE(struct, g2, 4); +CHECK_ALIGN(struct, g2, 4); +CHECK_OFFSET(struct, g2, c, 2); + +// Explicit attribute align on bit-field has precedence over packed attribute +// applied too the struct. +struct __attribute__((packed)) g3 { + char a; + __attribute__((aligned(16))) int b : 1; + char c; +}; + +CHECK_SIZE(struct, g3, 32); +CHECK_ALIGN(struct, g3, 16); +CHECK_OFFSET(struct, g3, c, 17); + +struct __attribute__((packed)) g4 { + char a; + __attribute__((aligned(2))) int b : 1; + char c; +}; + +CHECK_SIZE(struct, g4, 4); +CHECK_ALIGN(struct, g4, 2); +CHECK_OFFSET(struct, g4, c, 3); + +struct g5 { + char : 1; + __attribute__((aligned(1))) int n : 24; +}; +CHECK_SIZE(struct, g5, 4); +CHECK_ALIGN(struct, g5, 4); + +struct __attribute__((packed)) g6 { + char : 1; + __attribute__((aligned(1))) int n : 24; +}; +CHECK_SIZE(struct, g6, 4); +CHECK_ALIGN(struct, g6, 1); + +struct g7 { + char : 1; + __attribute__((aligned(1))) int n : 25; +}; +CHECK_SIZE(struct, g7, 8); +CHECK_ALIGN(struct, g7, 4); + +struct __attribute__((packed)) g8 { + char : 1; + __attribute__((aligned(1))) int n : 25; +}; +CHECK_SIZE(struct, g8, 5); +CHECK_ALIGN(struct, g8, 1); + +struct g9 { + __attribute__((aligned(1))) char a : 2, b : 2, c : 2, d : 2, e : 2; + int i; +}; +CHECK_SIZE(struct, g9, 12); +CHECK_ALIGN(struct, g9, 4); + +struct __attribute__((packed)) g10 { + __attribute__((aligned(1))) char a : 2, b : 2, c : 2, d : 2, e : 2; + int i; +}; +CHECK_SIZE(struct, g10, 9); +CHECK_ALIGN(struct, g10, 1); + +struct g11 { + char a; + __attribute__((aligned(1))) long long b : 62; + char c; +}; +#if defined(__arm__) || defined(__aarch64__) +CHECK_SIZE(struct, g11, 24); +CHECK_ALIGN(struct, g11, 8); +CHECK_OFFSET(struct, g11, c, 16); +#else +CHECK_SIZE(struct, g11, 16); +CHECK_ALIGN(struct, g11, 4); +CHECK_OFFSET(struct, g11, c, 12); +#endif + +struct __attribute__((packed)) g12 { + char a; + __attribute__((aligned(1))) long long b : 62; + char c; +}; +CHECK_SIZE(struct, g12, 10); +CHECK_ALIGN(struct, g12, 1); +CHECK_OFFSET(struct, g12, c, 9); + +struct g13 { + char a; + __attribute__((aligned(1))) long long : 0; + char c; +}; +#if defined(__arm__) || defined(__aarch64__) +CHECK_SIZE(struct, g13, 16); +CHECK_ALIGN(struct, g13, 8); +CHECK_OFFSET(struct, g13, c, 8); +#else +CHECK_SIZE(struct, g13, 5); +CHECK_ALIGN(struct, g13, 1); +CHECK_OFFSET(struct, g13, c, 4); +#endif + +struct __attribute__((packed)) g14 { + char a; + __attribute__((aligned(1))) long long : 0; + char c; +}; +#if defined(__arm__) || defined(__aarch64__) +CHECK_SIZE(struct, g14, 16); +CHECK_ALIGN(struct, g14, 8); +CHECK_OFFSET(struct, g14, c, 8); +#else +CHECK_SIZE(struct, g14, 5); +CHECK_ALIGN(struct, g14, 1); +CHECK_OFFSET(struct, g14, c, 4); +#endif