blob: b72e588ca7a445a386f640a101f6f60316be3997 [file] [log] [blame]
Anders Carlsson79474332009-07-18 20:20:21 +00001//=== ASTRecordLayoutBuilder.cpp - Helper class for building record layouts ==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "RecordLayoutBuilder.h"
11
12#include "clang/AST/Attr.h"
13#include "clang/AST/Decl.h"
14#include "clang/AST/Expr.h"
15#include "clang/AST/RecordLayout.h"
16#include "clang/Basic/TargetInfo.h"
17#include <llvm/Support/MathExtras.h>
18
19using namespace clang;
20
21ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
22 : Ctx(Ctx), Size(0), Alignment(8), StructPacking(0), NextOffset(0),
23 IsUnion(false) {}
24
25void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
26 IsUnion = D->isUnion();
27
28 if (const PackedAttr* PA = D->getAttr<PackedAttr>())
29 StructPacking = PA->getAlignment();
30
31 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
32 UpdateAlignment(AA->getAlignment());
33
34 // Layout each field, for now, just sequentially, respecting alignment. In
35 // the future, this will need to be tweakable by targets.
36 for (RecordDecl::field_iterator Field = D->field_begin(),
37 FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
38 LayoutField(*Field);
39
40 // Finally, round the size of the total struct up to the alignment of the
41 // struct itself.
42 FinishLayout();
43}
44
45void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
46 unsigned FieldPacking = StructPacking;
47 uint64_t FieldOffset = IsUnion ? 0 : Size;
48 uint64_t FieldSize;
49 unsigned FieldAlign;
50
51 // FIXME: Should this override struct packing? Probably we want to
52 // take the minimum?
53 if (const PackedAttr *PA = D->getAttr<PackedAttr>())
54 FieldPacking = PA->getAlignment();
55
56 if (const Expr *BitWidthExpr = D->getBitWidth()) {
57 // TODO: Need to check this algorithm on other targets!
58 // (tested on Linux-X86)
59 FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue();
60
61 std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
62 uint64_t TypeSize = FieldInfo.first;
63
64 // Determine the alignment of this bitfield. The packing
65 // attributes define a maximum and the alignment attribute defines
66 // a minimum.
67 // FIXME: What is the right behavior when the specified alignment
68 // is smaller than the specified packing?
69 FieldAlign = FieldInfo.second;
70 if (FieldPacking)
71 FieldAlign = std::min(FieldAlign, FieldPacking);
72 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
73 FieldAlign = std::max(FieldAlign, AA->getAlignment());
74
75 // Check if we need to add padding to give the field the correct
76 // alignment.
77 if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
78 FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
79
80 // Padding members don't affect overall alignment
81 if (!D->getIdentifier())
82 FieldAlign = 1;
83 } else {
84 if (D->getType()->isIncompleteArrayType()) {
85 // This is a flexible array member; we can't directly
86 // query getTypeInfo about these, so we figure it out here.
87 // Flexible array members don't have any size, but they
88 // have to be aligned appropriately for their element type.
89 FieldSize = 0;
90 const ArrayType* ATy = Ctx.getAsArrayType(D->getType());
91 FieldAlign = Ctx.getTypeAlign(ATy->getElementType());
92 } else if (const ReferenceType *RT = D->getType()->getAsReferenceType()) {
93 unsigned AS = RT->getPointeeType().getAddressSpace();
94 FieldSize = Ctx.Target.getPointerWidth(AS);
95 FieldAlign = Ctx.Target.getPointerAlign(AS);
96 } else {
97 std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
98 FieldSize = FieldInfo.first;
99 FieldAlign = FieldInfo.second;
100 }
101
102 // Determine the alignment of this bitfield. The packing
103 // attributes define a maximum and the alignment attribute defines
104 // a minimum. Additionally, the packing alignment must be at least
105 // a byte for non-bitfields.
106 //
107 // FIXME: What is the right behavior when the specified alignment
108 // is smaller than the specified packing?
109 if (FieldPacking)
110 FieldAlign = std::min(FieldAlign, std::max(8U, FieldPacking));
111 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
112 FieldAlign = std::max(FieldAlign, AA->getAlignment());
113
114 // Round up the current record size to the field's alignment boundary.
115 FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
116 }
117
118 // Place this field at the current location.
119 FieldOffsets.push_back(FieldOffset);
120
121 // Reserve space for this field.
122 if (IsUnion)
123 Size = std::max(Size, FieldSize);
124 else
125 Size = FieldOffset + FieldSize;
126
127 // Remember the next available offset.
128 NextOffset = Size;
129
130 // Remember max struct/class alignment.
131 UpdateAlignment(FieldAlign);
132}
133
134void ASTRecordLayoutBuilder::FinishLayout() {
135 // In C++, records cannot be of size 0.
136 if (Ctx.getLangOptions().CPlusPlus && Size == 0)
137 Size = 8;
138 // Finally, round the size of the record up to the alignment of the
139 // record itself.
140 Size = (Size + (Alignment-1)) & ~(Alignment-1);
141}
142
143void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
144 if (NewAlignment <= Alignment)
145 return;
146
147 assert(llvm::isPowerOf2_32(NewAlignment && "Alignment not a power of 2"));
148
149 Alignment = NewAlignment;
150}
151
152const ASTRecordLayout *
153ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
154 const RecordDecl *D) {
155 ASTRecordLayoutBuilder Builder(Ctx);
156
157 Builder.Layout(D);
158
159 return new ASTRecordLayout(Builder.Size, Builder.Alignment,
160 Builder.FieldOffsets.data(),
161 Builder.FieldOffsets.size());
162}