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