1 //=== 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/DeclCXX.h" 15 #include "clang/AST/DeclObjC.h" 16 #include "clang/AST/Expr.h" 17 #include "clang/AST/RecordLayout.h" 18 #include "clang/Basic/TargetInfo.h" 19 #include <llvm/Support/MathExtras.h> 20 21 using namespace clang; 22 23 ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) 24 : Ctx(Ctx), Size(0), Alignment(8), StructPacking(0), NextOffset(0), 25 IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8) {} 26 27 void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) { 28 if (RD->isPolymorphic() || RD->getNumVBases()) 29 { 30 // assert (RD->getNumBases() == 0 && "no polymorphic inheritance yet"); 31 int AS = 0; 32 UpdateAlignment(Ctx.Target.getPointerAlign(AS)); 33 Size += Ctx.Target.getPointerWidth(AS); 34 NextOffset = Size; 35 } 36 } 37 38 void 39 ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { 40 for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), 41 e = RD->bases_end(); i != e; ++i) { 42 if (!i->isVirtual()) { 43 const CXXRecordDecl *Base = 44 cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); 45 LayoutNonVirtualBase(Base); 46 } 47 } 48 } 49 50 void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) { 51 const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); 52 assert(BaseInfo.getDataSize() > 0 && 53 "FIXME: Handle empty classes."); 54 55 unsigned BaseAlign = BaseInfo.getNonVirtualAlign(); 56 uint64_t BaseSize = BaseInfo.getNonVirtualSize(); 57 58 // Round up the current record size to the base's alignment boundary. 59 Size = (Size + (BaseAlign-1)) & ~(BaseAlign-1); 60 61 // Add base class offsets. 62 Bases.push_back(RD); 63 BaseOffsets.push_back(Size); 64 65 // Reserve space for this base. 66 Size += BaseSize; 67 68 // Remember the next available offset. 69 NextOffset = Size; 70 71 // Remember max struct/class alignment. 72 UpdateAlignment(BaseAlign); 73 } 74 75 void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { 76 IsUnion = D->isUnion(); 77 78 if (const PackedAttr* PA = D->getAttr<PackedAttr>()) 79 StructPacking = PA->getAlignment(); 80 81 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) 82 UpdateAlignment(AA->getAlignment()); 83 84 // If this is a C++ class, lay out the nonvirtual bases. 85 if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { 86 LayoutVtable(RD); 87 LayoutNonVirtualBases(RD); 88 89 assert (RD->getNumVBases() == 0 90 && "FIXME: We don't support virtual bases yet!"); 91 // FIXME: We need to layout the virtual bases in the complete object layout. 92 } 93 94 LayoutFields(D); 95 96 NonVirtualSize = Size; 97 NonVirtualAlignment = Alignment; 98 99 // Finally, round the size of the total struct up to the alignment of the 100 // struct itself. 101 FinishLayout(); 102 } 103 104 void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, 105 const ObjCImplementationDecl *Impl) { 106 if (ObjCInterfaceDecl *SD = D->getSuperClass()) { 107 const ASTRecordLayout &SL = Ctx.getASTObjCInterfaceLayout(SD); 108 109 UpdateAlignment(SL.getAlignment()); 110 111 // We start laying out ivars not at the end of the superclass 112 // structure, but at the next byte following the last field. 113 Size = llvm::RoundUpToAlignment(SL.getDataSize(), 8); 114 NextOffset = Size; 115 } 116 117 if (const PackedAttr *PA = D->getAttr<PackedAttr>()) 118 StructPacking = PA->getAlignment(); 119 120 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) 121 UpdateAlignment(AA->getAlignment()); 122 123 // Layout each ivar sequentially. 124 llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; 125 Ctx.ShallowCollectObjCIvars(D, Ivars, Impl); 126 for (unsigned i = 0, e = Ivars.size(); i != e; ++i) 127 LayoutField(Ivars[i]); 128 129 // Finally, round the size of the total struct up to the alignment of the 130 // struct itself. 131 FinishLayout(); 132 } 133 134 void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { 135 // Layout each field, for now, just sequentially, respecting alignment. In 136 // the future, this will need to be tweakable by targets. 137 for (RecordDecl::field_iterator Field = D->field_begin(), 138 FieldEnd = D->field_end(); Field != FieldEnd; ++Field) 139 LayoutField(*Field); 140 } 141 142 void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { 143 unsigned FieldPacking = StructPacking; 144 uint64_t FieldOffset = IsUnion ? 0 : Size; 145 uint64_t FieldSize; 146 unsigned FieldAlign; 147 148 // FIXME: Should this override struct packing? Probably we want to 149 // take the minimum? 150 if (const PackedAttr *PA = D->getAttr<PackedAttr>()) 151 FieldPacking = PA->getAlignment(); 152 153 if (const Expr *BitWidthExpr = D->getBitWidth()) { 154 // TODO: Need to check this algorithm on other targets! 155 // (tested on Linux-X86) 156 FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue(); 157 158 std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType()); 159 uint64_t TypeSize = FieldInfo.first; 160 161 // Determine the alignment of this bitfield. The packing 162 // attributes define a maximum and the alignment attribute defines 163 // a minimum. 164 // FIXME: What is the right behavior when the specified alignment 165 // is smaller than the specified packing? 166 FieldAlign = FieldInfo.second; 167 if (FieldPacking) 168 FieldAlign = std::min(FieldAlign, FieldPacking); 169 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) 170 FieldAlign = std::max(FieldAlign, AA->getAlignment()); 171 172 // Check if we need to add padding to give the field the correct 173 // alignment. 174 if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) 175 FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); 176 177 // Padding members don't affect overall alignment 178 if (!D->getIdentifier()) 179 FieldAlign = 1; 180 } else { 181 if (D->getType()->isIncompleteArrayType()) { 182 // This is a flexible array member; we can't directly 183 // query getTypeInfo about these, so we figure it out here. 184 // Flexible array members don't have any size, but they 185 // have to be aligned appropriately for their element type. 186 FieldSize = 0; 187 const ArrayType* ATy = Ctx.getAsArrayType(D->getType()); 188 FieldAlign = Ctx.getTypeAlign(ATy->getElementType()); 189 } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) { 190 unsigned AS = RT->getPointeeType().getAddressSpace(); 191 FieldSize = Ctx.Target.getPointerWidth(AS); 192 FieldAlign = Ctx.Target.getPointerAlign(AS); 193 } else { 194 std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType()); 195 FieldSize = FieldInfo.first; 196 FieldAlign = FieldInfo.second; 197 } 198 199 // Determine the alignment of this bitfield. The packing 200 // attributes define a maximum and the alignment attribute defines 201 // a minimum. Additionally, the packing alignment must be at least 202 // a byte for non-bitfields. 203 // 204 // FIXME: What is the right behavior when the specified alignment 205 // is smaller than the specified packing? 206 if (FieldPacking) 207 FieldAlign = std::min(FieldAlign, std::max(8U, FieldPacking)); 208 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) 209 FieldAlign = std::max(FieldAlign, AA->getAlignment()); 210 211 // Round up the current record size to the field's alignment boundary. 212 FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); 213 } 214 215 // Place this field at the current location. 216 FieldOffsets.push_back(FieldOffset); 217 218 // Reserve space for this field. 219 if (IsUnion) 220 Size = std::max(Size, FieldSize); 221 else 222 Size = FieldOffset + FieldSize; 223 224 // Remember the next available offset. 225 NextOffset = Size; 226 227 // Remember max struct/class alignment. 228 UpdateAlignment(FieldAlign); 229 } 230 231 void ASTRecordLayoutBuilder::FinishLayout() { 232 // In C++, records cannot be of size 0. 233 if (Ctx.getLangOptions().CPlusPlus && Size == 0) 234 Size = 8; 235 // Finally, round the size of the record up to the alignment of the 236 // record itself. 237 Size = (Size + (Alignment-1)) & ~(Alignment-1); 238 } 239 240 void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { 241 if (NewAlignment <= Alignment) 242 return; 243 244 assert(llvm::isPowerOf2_32(NewAlignment && "Alignment not a power of 2")); 245 246 Alignment = NewAlignment; 247 } 248 249 const ASTRecordLayout * 250 ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, 251 const RecordDecl *D) { 252 ASTRecordLayoutBuilder Builder(Ctx); 253 254 Builder.Layout(D); 255 256 if (!isa<CXXRecordDecl>(D)) 257 return new ASTRecordLayout(Builder.Size, Builder.Alignment, Builder.Size, 258 Builder.FieldOffsets.data(), 259 Builder.FieldOffsets.size()); 260 261 // FIXME: This is not always correct. See the part about bitfields at 262 // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info. 263 // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout. 264 bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD(); 265 266 assert(Builder.Bases.size() == Builder.BaseOffsets.size() && 267 "Base offsets vector must be same size as bases vector!"); 268 269 // FIXME: This should be done in FinalizeLayout. 270 uint64_t DataSize = 271 IsPODForThePurposeOfLayout ? Builder.Size : Builder.NextOffset; 272 uint64_t NonVirtualSize = 273 IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; 274 275 return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize, 276 Builder.FieldOffsets.data(), 277 Builder.FieldOffsets.size(), 278 NonVirtualSize, 279 Builder.NonVirtualAlignment, 280 Builder.Bases.data(), 281 Builder.BaseOffsets.data(), 282 Builder.Bases.size()); 283 } 284 285 const ASTRecordLayout * 286 ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, 287 const ObjCInterfaceDecl *D, 288 const ObjCImplementationDecl *Impl) { 289 ASTRecordLayoutBuilder Builder(Ctx); 290 291 Builder.Layout(D, Impl); 292 293 return new ASTRecordLayout(Builder.Size, Builder.Alignment, 294 Builder.NextOffset, 295 Builder.FieldOffsets.data(), 296 Builder.FieldOffsets.size()); 297 } 298