diff options
author | John McCall <rjmccall@apple.com> | 2011-01-20 07:57:12 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-01-20 07:57:12 +0000 |
commit | ba4f5d5754c8291690d01ca9581926673d69b24c (patch) | |
tree | ba5c8463382801f9f2f55641e03278da8c565d69 | |
parent | 9eefa229dfb71400a6bbee326420a7f0e2e91f1f (diff) |
Fix the computation of alignment for fields of packed+aligned structs.
Part of the fix for PR8413.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123904 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Decl.h | 9 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 34 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 19 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 9 | ||||
-rw-r--r-- | test/CodeGen/packed-structure.c | 13 |
5 files changed, 69 insertions, 15 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index fe4b71ccc1..25424ce853 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1728,12 +1728,15 @@ public: class FieldDecl : public DeclaratorDecl { // FIXME: This can be packed into the bitfields in Decl. bool Mutable : 1; + mutable unsigned CachedFieldIndex : 31; + Expr *BitWidth; protected: FieldDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable) - : DeclaratorDecl(DK, DC, L, Id, T, TInfo), Mutable(Mutable), BitWidth(BW) { + : DeclaratorDecl(DK, DC, L, Id, T, TInfo), + Mutable(Mutable), CachedFieldIndex(0), BitWidth(BW) { } public: @@ -1741,6 +1744,10 @@ public: SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable); + /// getFieldIndex - Returns the index of this field within its record, + /// as appropriate for passing to ASTRecordLayout::getFieldOffset. + unsigned getFieldIndex() const; + /// isMutable - Determines whether this field is mutable (C++ only). bool isMutable() const { return Mutable; } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index d1ac00871a..043d56a98d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -590,8 +590,11 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { } } + // If we're using the align attribute only, just ignore everything + // else about the declaration and its type. if (UseAlignAttrOnly) { - // ignore type of value + // do nothing + } else if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { QualType T = VD->getType(); if (const ReferenceType* RT = T->getAs<ReferenceType>()) { @@ -617,11 +620,30 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { } Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); } - if (const FieldDecl *FD = dyn_cast<FieldDecl>(VD)) { - // In the case of a field in a packed struct, we want the minimum - // of the alignment of the field and the alignment of the struct. - Align = std::min(Align, - getPreferredTypeAlign(FD->getParent()->getTypeForDecl())); + + // Fields can be subject to extra alignment constraints, like if + // the field is packed, the struct is packed, or the struct has a + // a max-field-alignment constraint (#pragma pack). So calculate + // the actual alignment of the field within the struct, and then + // (as we're expected to) constrain that by the alignment of the type. + if (const FieldDecl *field = dyn_cast<FieldDecl>(VD)) { + // So calculate the alignment of the field. + const ASTRecordLayout &layout = getASTRecordLayout(field->getParent()); + + // Start with the record's overall alignment. + unsigned fieldAlign = layout.getAlignment(); + + // Use the GCD of that and the offset within the record. + uint64_t offset = layout.getFieldOffset(field->getFieldIndex()); + if (offset > 0) { + // Alignment is always a power of 2, so the GCD will be a power of 2, + // which means we get to do this crazy thing instead of Euclid's. + uint64_t lowBitOfOffset = offset & (~offset + 1); + if (lowBitOfOffset < fieldAlign) + fieldAlign = static_cast<unsigned>(lowBitOfOffset); + } + + Align = std::min(Align, fieldAlign); } } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 9e2e8763f8..b1da849ae1 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1881,6 +1881,25 @@ bool FieldDecl::isAnonymousStructOrUnion() const { return false; } +unsigned FieldDecl::getFieldIndex() const { + if (CachedFieldIndex) return CachedFieldIndex - 1; + + unsigned index = 0; + RecordDecl::field_iterator + i = getParent()->field_begin(), e = getParent()->field_end(); + while (true) { + assert(i != e && "failed to find field in parent!"); + if (*i == this) + break; + + ++i; + ++index; + } + + CachedFieldIndex = index + 1; + return index; +} + //===----------------------------------------------------------------------===// // TagDecl Implementation //===----------------------------------------------------------------------===// diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index f262a4acff..afce24e625 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1565,14 +1565,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) { return false; RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); - unsigned i = 0; - // FIXME: It would be nice if we didn't have to loop here! - for (RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); - Field != FieldEnd; (void)++Field, ++i) { - if (*Field == MemberDecl) - break; - } + unsigned i = MemberDecl->getFieldIndex(); assert(i < RL.getFieldCount() && "offsetof field in wrong type"); Result += Info.Ctx.toCharUnitsFromBits(RL.getFieldOffset(i)); CurrentType = MemberDecl->getType().getNonReferenceType(); diff --git a/test/CodeGen/packed-structure.c b/test/CodeGen/packed-structure.c index 2934d01d64..731a50bb07 100644 --- a/test/CodeGen/packed-structure.c +++ b/test/CodeGen/packed-structure.c @@ -87,3 +87,16 @@ int s2_load_y(struct s2 *a) { return a->y; } // CHECK-FUNCTIONS: define void @s2_copy // CHECK-FUNCTIONS: call void @llvm.memcpy.p0i8.p0i8.i64(i8* {{.*}}, i8* {{.*}}, i64 8, i32 2, i1 false) void s2_copy(struct s2 *a, struct s2 *b) { *b = *a; } + +struct __attribute__((packed, aligned)) s3 { + short aShort; + int anInt; +}; +// CHECK-GLOBAL: @s3_1 = global i32 2 +int s3_1 = __alignof(((struct s3*) 0)->anInt); +// CHECK-FUNCTIONS: define i32 @test3( +int test3(struct s3 *ptr) { + // CHECK-FUNCTIONS: [[PTR:%.*]] = getelementptr inbounds {{%.*}}* {{%.*}}, i32 0, i32 1 + // CHECK-FUNCTIONS-NEXT: load i32* [[PTR]], align 2 + return ptr->anInt; +} |