void CGRecordLowering::insertPadding() { std::vector<std::pair<CharUnits, CharUnits> > Padding; CharUnits Size = CharUnits::Zero(); for (std::vector<MemberInfo>::const_iterator Member = Members.begin(), MemberEnd = Members.end(); Member != MemberEnd; ++Member) { if (!Member->Data) continue; CharUnits Offset = Member->Offset; assert(Offset >= Size); // Insert padding if we need to. if (Offset != Size.RoundUpToAlignment(Packed ? CharUnits::One() : getAlignment(Member->Data))) Padding.push_back(std::make_pair(Size, Offset - Size)); Size = Offset + getSize(Member->Data); } if (Padding.empty()) return; // Add the padding to the Members list and sort it. for (std::vector<std::pair<CharUnits, CharUnits> >::const_iterator Pad = Padding.begin(), PadEnd = Padding.end(); Pad != PadEnd; ++Pad) Members.push_back(StorageInfo(Pad->first, getByteArrayType(Pad->second))); std::stable_sort(Members.begin(), Members.end()); }
bool CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) { const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(RD); CharUnits NonVirtualSize = Layout.getNonVirtualSize(); CharUnits NonVirtualAlign = Layout.getNonVirtualAlign(); CharUnits AlignedNonVirtualTypeSize = NonVirtualSize.RoundUpToAlignment(NonVirtualAlign); // First check if we can use the same fields as for the complete class. CharUnits RecordSize = Layout.getSize(); if (AlignedNonVirtualTypeSize == RecordSize) return true; // Check if we need padding. CharUnits AlignedNextFieldOffset = NextFieldOffset.RoundUpToAlignment(getAlignmentAsLLVMStruct()); if (AlignedNextFieldOffset > AlignedNonVirtualTypeSize) { assert(!Packed && "cannot layout even as packed struct"); return false; // Needs packing. } bool needsPadding = (AlignedNonVirtualTypeSize != AlignedNextFieldOffset); if (needsPadding) { CharUnits NumBytes = AlignedNonVirtualTypeSize - AlignedNextFieldOffset; FieldTypes.push_back(getByteArrayType(NumBytes)); } BaseSubobjectType = llvm::StructType::create(Types.getLLVMContext(), FieldTypes, "", Packed); Types.addRecordTypeName(RD, BaseSubobjectType, ".base"); // Pull the padding back off. if (needsPadding) FieldTypes.pop_back(); return true; }
CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, llvm::StructType *Ty) { CGRecordLayoutBuilder Builder(*this); Builder.Layout(D); Ty->setBody(Builder.FieldTypes, Builder.Packed); // If we're in C++, compute the base subobject type. llvm::StructType *BaseTy = 0; if (isa<CXXRecordDecl>(D) && !D->isUnion()) { BaseTy = Builder.BaseSubobjectType; if (!BaseTy) BaseTy = Ty; } CGRecordLayout *RL = new CGRecordLayout(Ty, BaseTy, Builder.IsZeroInitializable, Builder.IsZeroInitializableAsBase); RL->NonVirtualBases.swap(Builder.NonVirtualBases); RL->CompleteObjectVirtualBases.swap(Builder.VirtualBases); // Add all the field numbers. RL->FieldInfo.swap(Builder.Fields); // Add bitfield info. RL->BitFields.swap(Builder.BitFields); // Dump the layout, if requested. if (getContext().getLangOpts().DumpRecordLayouts) { llvm::outs() << "\n*** Dumping IRgen Record Layout\n"; llvm::outs() << "Record: "; D->dump(llvm::outs()); llvm::outs() << "\nLayout: "; RL->print(llvm::outs()); } #ifndef NDEBUG // Verify that the computed LLVM struct size matches the AST layout size. const ASTRecordLayout &Layout = getContext().getASTRecordLayout(D); uint64_t TypeSizeInBits = getContext().toBits(Layout.getSize()); assert(TypeSizeInBits == getDataLayout().getTypeAllocSizeInBits(Ty) && "Type size mismatch!"); if (BaseTy) { CharUnits NonVirtualSize = Layout.getNonVirtualSize(); CharUnits NonVirtualAlign = Layout.getNonVirtualAlign(); CharUnits AlignedNonVirtualTypeSize = NonVirtualSize.RoundUpToAlignment(NonVirtualAlign); uint64_t AlignedNonVirtualTypeSizeInBits = getContext().toBits(AlignedNonVirtualTypeSize); assert(AlignedNonVirtualTypeSizeInBits == getDataLayout().getTypeAllocSizeInBits(BaseTy) && "Type size mismatch!"); } // Verify that the LLVM and AST field offsets agree. llvm::StructType *ST = dyn_cast<llvm::StructType>(RL->getLLVMType()); const llvm::StructLayout *SL = getDataLayout().getStructLayout(ST); const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D); RecordDecl::field_iterator it = D->field_begin(); for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) { const FieldDecl *FD = *it; // For non-bit-fields, just check that the LLVM struct offset matches the // AST offset. if (!FD->isBitField()) { unsigned FieldNo = RL->getLLVMFieldNo(FD); assert(AST_RL.getFieldOffset(i) == SL->getElementOffsetInBits(FieldNo) && "Invalid field offset!"); continue; } // Ignore unnamed bit-fields. if (!FD->getDeclName()) continue; // Don't inspect zero-length bitfields. if (FD->getBitWidthValue(getContext()) == 0) continue; const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD); llvm::Type *ElementTy = ST->getTypeAtIndex(RL->getLLVMFieldNo(FD)); // Unions have overlapping elements dictating their layout, but for // non-unions we can verify that this section of the layout is the exact // expected size. if (D->isUnion()) { // For unions we verify that the start is zero and the size // is in-bounds. However, on BE systems, the offset may be non-zero, but // the size + offset should match the storage size in that case as it // "starts" at the back. if (getDataLayout().isBigEndian()) assert(static_cast<unsigned>(Info.Offset + Info.Size) == Info.StorageSize && "Big endian union bitfield does not end at the back"); else assert(Info.Offset == 0 && "Little endian union bitfield with a non-zero offset"); assert(Info.StorageSize <= SL->getSizeInBits() && "Union not large enough for bitfield storage"); } else { assert(Info.StorageSize == getDataLayout().getTypeAllocSizeInBits(ElementTy) && "Storage size does not match the element type size"); } assert(Info.Size > 0 && "Empty bitfield!"); assert(static_cast<unsigned>(Info.Offset) + Info.Size <= Info.StorageSize && "Bitfield outside of its allocated storage"); } #endif return RL; }