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