CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, llvm::StructType *Ty) { CGRecordLowering Builder(*this, D, /*Packed=*/false); Builder.lower(/*NonVirtualBaseType=*/false); // If we're in C++, compute the base subobject type. llvm::StructType *BaseTy = nullptr; if (isa<CXXRecordDecl>(D) && !D->isUnion() && !D->hasAttr<FinalAttr>()) { BaseTy = Ty; if (Builder.Layout.getNonVirtualSize() != Builder.Layout.getSize()) { CGRecordLowering BaseBuilder(*this, D, /*Packed=*/Builder.Packed); BaseBuilder.lower(/*NonVirtualBaseType=*/true); BaseTy = llvm::StructType::create( getLLVMContext(), BaseBuilder.FieldTypes, "", BaseBuilder.Packed); addRecordTypeName(D, BaseTy, ".base"); // BaseTy and Ty must agree on their packedness for getLLVMFieldNo to work // on both of them with the same index. assert(Builder.Packed == BaseBuilder.Packed && "Non-virtual and complete types must agree on packedness"); } } // Fill in the struct *after* computing the base type. Filling in the body // signifies that the type is no longer opaque and record layout is complete, // but we may need to recursively layout D while laying D out as a base type. Ty->setBody(Builder.FieldTypes, Builder.Packed); 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(); uint64_t AlignedNonVirtualTypeSizeInBits = getContext().toBits(NonVirtualSize); assert(AlignedNonVirtualTypeSizeInBits == getDataLayout().getTypeAllocSizeInBits(BaseTy) && "Type size mismatch!"); } // Verify that the LLVM and AST field offsets agree. llvm::StructType *ST = 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->isZeroLengthBitField(getContext())) 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; }
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; }