const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D)
const;
- void DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS) const;
+ void DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS,
+ bool Simple = false) const;
/// getASTObjCImplementationLayout - Get or compute information about
/// the layout of the specified Objective-C implementation. This may
#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
#include "clang/AST/DeclBase.h"
+#include "clang/AST/CharUnits.h"
+#include "llvm/ADT/DenseMap.h"
namespace clang {
/// The default implementation of this method is a no-op.
virtual void PrintStats();
+
+ /// \brief Perform layout on the given record.
+ ///
+ /// This routine allows the external AST source to provide an specific
+ /// layout for a record, overriding the layout that would normally be
+ /// constructed. It is intended for clients who receive specific layout
+ /// details rather than source code (such as LLDB). The client is expected
+ /// to fill in the field offsets, base offsets, virtual base offsets, and
+ /// complete object size.
+ ///
+ /// \param Record The record whose layout is being requested.
+ ///
+ /// \param Size The final size of the record, in bits.
+ ///
+ /// \param Alignment The final alignment of the record, in bits.
+ ///
+ /// \param FieldOffsets The offset of each of the fields within the record,
+ /// expressed in bits. All of the fields must be provided with offsets.
+ ///
+ /// \param BaseOffsets The offset of each of the direct, non-virtual base
+ /// classes. If any bases are not given offsets, the bases will be laid
+ /// out according to the ABI.
+ ///
+ /// \param VirtualBaseOffsets The offset of each of the virtual base classes
+ /// (either direct or not). If any bases are not given offsets, the bases will be laid
+ /// out according to the ABI.
+ ///
+ /// \returns true if the record layout was provided, false otherwise.
+ virtual bool
+ layoutRecordType(const RecordDecl *Record,
+ uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets)
+ {
+ return false;
+ }
+
//===--------------------------------------------------------------------===//
// Queries for performance analysis.
//===--------------------------------------------------------------------===//
BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision")
BENIGN_LANGOPT(CatchUndefined , 1, 0, "catching undefined behavior at run time")
BENIGN_LANGOPT(DumpRecordLayouts , 1, 0, "dumping the layout of IRgen'd records")
+BENIGN_LANGOPT(DumpRecordLayoutsSimple , 1, 0, "dumping the layout of IRgen'd records in a simple form")
BENIGN_LANGOPT(DumpVTableLayouts , 1, 0, "dumping the layouts of emitted vtables")
LANGOPT(NoConstantCFStrings , 1, 0, "no constant CoreFoundation strings")
BENIGN_LANGOPT(InlineVisibilityHidden , 1, 0, "hidden default visibility for inline C++ methods")
HelpText<"Print the amount of time each phase of compilation takes">;
def fdump_record_layouts : Flag<"-fdump-record-layouts">,
HelpText<"Dump record layout information">;
+def fdump_record_layouts_simple : Flag<"-fdump-record-layouts-simple">,
+ HelpText<"Dump record layout information in a simple form used for testing">;
def fix_what_you_can : Flag<"-fix-what-you-can">,
HelpText<"Apply fix-it advice even in the presence of unfixable errors">;
def fix_only_warnings : Flag<"-fix-only-warnings">,
def mllvm : Separate<"-mllvm">,
HelpText<"Additional arguments to forward to LLVM's option processing">;
+def foverride_record_layout_EQ : Joined<"-foverride-record-layout=">,
+ HelpText<"Override record layouts with those in the given file">;
+
//===----------------------------------------------------------------------===//
// Language Options
//===----------------------------------------------------------------------===//
/// should only be used for debugging and experimental features.
std::vector<std::string> LLVMArgs;
+ /// \brief File name of the file that will provide record layouts
+ /// (in the format produced by -fdump-record-layouts).
+ std::string OverrideRecordLayoutsFile;
+
public:
FrontendOptions() {
DisableFree = 0;
--- /dev/null
+//===--- LayoutOverrideSource.h --Override Record Layouts -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_LAYOUTOVERRIDESOURCE_H
+#define LLVM_CLANG_FRONTEND_LAYOUTOVERRIDESOURCE_H
+
+#include "clang/AST/ExternalASTSource.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+ /// \brief An external AST source that overrides the layout of
+ /// a specified set of record types.
+ ///
+ /// This class is used only for testing the ability of external AST sources
+ /// to override the layout of record types. Its input is the output format
+ /// of the command-line argument -fdump-record-layouts.
+ class LayoutOverrideSource : public ExternalASTSource {
+ /// \brief The layout of a given record.
+ struct Layout {
+ /// \brief The size of the record.
+ uint64_t Size;
+
+ /// \brief The alignment of the record.
+ uint64_t Align;
+
+ /// \brief The offsets of the fields, in source order.
+ llvm::SmallVector<uint64_t, 8> FieldOffsets;
+ };
+
+ /// \brief The set of layouts that will be overridden.
+ llvm::StringMap<Layout> Layouts;
+
+ public:
+ /// \brief Create a new AST source that overrides the layout of some
+ /// set of record types.
+ ///
+ /// The file is the result of passing -fdump-record-layouts to a file.
+ explicit LayoutOverrideSource(llvm::StringRef Filename);
+
+ /// \brief If this particular record type has an overridden layout,
+ /// return that layout.
+ virtual bool
+ layoutRecordType(const RecordDecl *Record,
+ uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets);
+
+ /// \brief Dump the overridden layouts.
+ void dump();
+ };
+}
+
+#endif
SmallVector<uint64_t, 16> FieldOffsets;
+ /// \brief Whether the external AST source has provided a layout for this
+ /// record.
+ unsigned ExternalLayout : 1;
+
/// Packed - Whether the record is packed or not.
unsigned Packed : 1;
/// avoid visiting virtual bases more than once.
llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
+ /// \brief Externally-provided size.
+ uint64_t ExternalSize;
+
+ /// \brief Externally-provided alignment.
+ uint64_t ExternalAlign;
+
+ /// \brief Externally-provided field offsets.
+ llvm::DenseMap<const FieldDecl *, uint64_t> ExternalFieldOffsets;
+
+ /// \brief Externally-provided direct, non-virtual base offsets.
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> ExternalBaseOffsets;
+
+ /// \brief Externally-provided virtual base offsets.
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> ExternalVirtualBaseOffsets;
+
RecordLayoutBuilder(const ASTContext &Context,
EmptySubobjectMap *EmptySubobjects)
: Context(Context), EmptySubobjects(EmptySubobjects), Size(0),
Alignment(CharUnits::One()), UnpackedAlignment(CharUnits::One()),
- Packed(false), IsUnion(false),
+ ExternalLayout(false), Packed(false), IsUnion(false),
IsMac68kAlign(false), IsMsStruct(false),
UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()),
CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base->Class);
+
+ CharUnits Offset;
+
+ // Query the external layout to see if it provides an offset.
+ bool HasExternalLayout = false;
+ if (ExternalLayout) {
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits>::iterator Known;
+ if (Base->IsVirtual) {
+ Known = ExternalVirtualBaseOffsets.find(Base->Class);
+ if (Known != ExternalVirtualBaseOffsets.end()) {
+ Offset = Known->second;
+ HasExternalLayout = true;
+ }
+ } else {
+ Known = ExternalBaseOffsets.find(Base->Class);
+ if (Known != ExternalBaseOffsets.end()) {
+ Offset = Known->second;
+ HasExternalLayout = true;
+ }
+ }
+ }
+
// If we have an empty base class, try to place it at offset 0.
if (Base->Class->isEmpty() &&
+ (!HasExternalLayout || Offset == CharUnits::Zero()) &&
EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) {
setSize(std::max(getSize(), Layout.getSize()));
UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment);
}
- // Round up the current record size to the base's alignment boundary.
- CharUnits Offset = getDataSize().RoundUpToAlignment(BaseAlign);
-
- // Try to place the base.
- while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset))
- Offset += BaseAlign;
+ if (!HasExternalLayout) {
+ // Round up the current record size to the base's alignment boundary.
+ Offset = getDataSize().RoundUpToAlignment(BaseAlign);
+ // Try to place the base.
+ while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset))
+ Offset += BaseAlign;
+ } else {
+ bool Allowed = EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset);
+ (void)Allowed;
+ assert(Allowed && "Base subobject externally placed at overlapping offset");
+ }
+
if (!Base->Class->isEmpty()) {
// Update the data size.
setDataSize(Offset + Layout.getNonVirtualSize());
if (unsigned MaxAlign = D->getMaxAlignment())
UpdateAlignment(Context.toCharUnitsFromBits(MaxAlign));
}
+
+ // If there is an external AST source, ask it for the various offsets.
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
+ if (ExternalASTSource *External = Context.getExternalSource()) {
+ ExternalLayout = External->layoutRecordType(RD,
+ ExternalSize,
+ ExternalAlign,
+ ExternalFieldOffsets,
+ ExternalBaseOffsets,
+ ExternalVirtualBaseOffsets);
+
+ // Update based on external alignment.
+ if (ExternalLayout) {
+ Alignment = Context.toCharUnitsFromBits(ExternalAlign);
+ UnpackedAlignment = Alignment;
+ }
+ }
}
void RecordLayoutBuilder::Layout(const RecordDecl *D) {
uint64_t TypeSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
+ if (ExternalLayout) {
+ assert(ExternalFieldOffsets.find(D) != ExternalFieldOffsets.end() &&
+ "Field does not have an external offset");
+ FieldOffset = ExternalFieldOffsets[D];
+ }
+
// This check is needed for 'long long' in -m32 mode.
if (IsMsStruct && (TypeSize > FieldAlign) &&
(Context.hasSameType(D->getType(),
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
}
- // Check if we need to add padding to give the field the correct alignment.
- if (FieldSize == 0 || (MaxFieldAlignment.isZero() &&
- (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize))
- FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+ if (!ExternalLayout) {
+ // Check if we need to add padding to give the field the correct alignment.
+ if (FieldSize == 0 ||
+ (MaxFieldAlignment.isZero() &&
+ (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize))
+ FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
- if (FieldSize == 0 ||
- (MaxFieldAlignment.isZero() &&
- (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize))
- UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
- UnpackedFieldAlign);
+ if (FieldSize == 0 ||
+ (MaxFieldAlignment.isZero() &&
+ (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize))
+ UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
+ UnpackedFieldAlign);
+ }
// Padding members don't affect overall alignment, unless zero length bitfield
// alignment is enabled.
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
- CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, UnpackedFieldOffset,
- UnpackedFieldAlign, FieldPacked, D);
+ if (!ExternalLayout)
+ CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, UnpackedFieldOffset,
+ UnpackedFieldAlign, FieldPacked, D);
// Update DataSize to include the last byte containing (part of) the bitfield.
if (IsUnion) {
Context.toCharUnitsFromBits(UnpackedFieldAlign));
}
-void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
+void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
if (D->isBitField()) {
LayoutBitField(D);
return;
CharUnits FieldSize;
CharUnits FieldAlign;
+ if (ExternalLayout) {
+ assert(ExternalFieldOffsets.find(D) != ExternalFieldOffsets.end() &&
+ "Field does not have an external offset");
+ FieldOffset = Context.toCharUnitsFromBits(ExternalFieldOffsets[D]);
+ }
+
+
if (D->getType()->isIncompleteArrayType()) {
// This is a flexible array member; we can't directly
// query getTypeInfo about these, so we figure it out here.
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment);
}
- // Round up the current record size to the field's alignment boundary.
- FieldOffset = FieldOffset.RoundUpToAlignment(FieldAlign);
- UnpackedFieldOffset =
- UnpackedFieldOffset.RoundUpToAlignment(UnpackedFieldAlign);
-
- if (!IsUnion && EmptySubobjects) {
- // Check if we can place the field at this offset.
- while (!EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset)) {
- // We couldn't place the field at the offset. Try again at a new offset.
- FieldOffset += FieldAlign;
+ if (!ExternalLayout) {
+ // Round up the current record size to the field's alignment boundary.
+ FieldOffset = FieldOffset.RoundUpToAlignment(FieldAlign);
+ UnpackedFieldOffset =
+ UnpackedFieldOffset.RoundUpToAlignment(UnpackedFieldAlign);
+
+ if (!IsUnion && EmptySubobjects) {
+ // Check if we can place the field at this offset.
+ while (!EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset)) {
+ // We couldn't place the field at the offset. Try again at a new offset.
+ FieldOffset += FieldAlign;
+ }
}
+ } else if (!IsUnion && EmptySubobjects) {
+ // Record the fact that we're placing a field at this offset.
+ bool Allowed = EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset);
+ (void)Allowed;
+ assert(Allowed && "Externally-placed field cannot be placed here");
}
-
+
// Place this field at the current location.
FieldOffsets.push_back(Context.toBits(FieldOffset));
- CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffset,
- Context.toBits(UnpackedFieldOffset),
- Context.toBits(UnpackedFieldAlign), FieldPacked, D);
+ if (!ExternalLayout)
+ CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffset,
+ Context.toBits(UnpackedFieldOffset),
+ Context.toBits(UnpackedFieldAlign), FieldPacked, D);
// Reserve space for this field.
uint64_t FieldSizeInBits = Context.toBits(FieldSize);
void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment,
CharUnits UnpackedNewAlignment) {
- // The alignment is not modified when using 'mac68k' alignment.
- if (IsMac68kAlign)
+ // The alignment is not modified when using 'mac68k' alignment or when
+ // we have an externally-supplied layout.
+ if (IsMac68kAlign || ExternalLayout)
return;
if (NewAlignment > Alignment) {
if (getLangOptions().DumpRecordLayouts) {
llvm::errs() << "\n*** Dumping AST Record Layout\n";
- DumpRecordLayout(D, llvm::errs());
+ DumpRecordLayout(D, llvm::errs(), getLangOptions().DumpRecordLayoutsSimple);
}
return *NewEntry;
}
void ASTContext::DumpRecordLayout(const RecordDecl *RD,
- raw_ostream &OS) const {
+ raw_ostream &OS,
+ bool Simple) const {
const ASTRecordLayout &Info = getASTRecordLayout(RD);
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- return DumpCXXRecordLayout(OS, CXXRD, *this, CharUnits(), 0, 0,
- /*IncludeVirtualBases=*/true);
+ if (!Simple)
+ return DumpCXXRecordLayout(OS, CXXRD, *this, CharUnits(), 0, 0,
+ /*IncludeVirtualBases=*/true);
OS << "Type: " << getTypeDeclType(RD).getAsString() << "\n";
- OS << "Record: ";
- RD->dump();
+ if (!Simple) {
+ OS << "Record: ";
+ RD->dump();
+ }
OS << "\nLayout: ";
OS << "<ASTRecordLayout\n";
OS << " Size:" << toBits(Info.getSize()) << "\n";
InitHeaderSearch.cpp
InitPreprocessor.cpp
LangStandards.cpp
+ LayoutOverrideSource.cpp
LogDiagnosticPrinter.cpp
MultiplexConsumer.cpp
PrintPreprocessedOutput.cpp
Res.push_back("-mllvm");
Res.push_back(Opts.LLVMArgs[i]);
}
+ if (!Opts.OverrideRecordLayoutsFile.empty())
+ Res.push_back("-foverride-record-layout=" + Opts.OverrideRecordLayoutsFile);
}
static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
Res.push_back("-ffast-math");
if (Opts.Static)
Res.push_back("-static-define");
- if (Opts.DumpRecordLayouts)
+ if (Opts.DumpRecordLayoutsSimple)
+ Res.push_back("-fdump-record-layouts-simple");
+ else if (Opts.DumpRecordLayouts)
Res.push_back("-fdump-record-layouts");
if (Opts.DumpVTableLayouts)
Res.push_back("-fdump-vtable-layouts");
Opts.FixOnlyWarnings = Args.hasArg(OPT_fix_only_warnings);
Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile);
Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp);
-
+ Opts.OverrideRecordLayoutsFile
+ = Args.getLastArgValue(OPT_foverride_record_layout_EQ);
Opts.ARCMTAction = FrontendOptions::ARCMT_None;
if (const Arg *A = Args.getLastArg(OPT_arcmt_check,
OPT_arcmt_modify,
Opts.PackStruct = Args.getLastArgIntValue(OPT_fpack_struct, 0, Diags);
Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags);
Opts.Static = Args.hasArg(OPT_static_define);
- Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts);
+ Opts.DumpRecordLayoutsSimple = Args.hasArg(OPT_fdump_record_layouts_simple);
+ Opts.DumpRecordLayouts = Opts.DumpRecordLayoutsSimple
+ || Args.hasArg(OPT_fdump_record_layouts);
Opts.DumpVTableLayouts = Args.hasArg(OPT_fdump_vtable_layouts);
Opts.SpellChecking = !Args.hasArg(OPT_fno_spell_checking);
Opts.NoBitFieldTypeAlign = Args.hasArg(OPT_fno_bitfield_type_align);
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Frontend/LayoutOverrideSource.h"
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Serialization/ASTDeserializationListener.h"
PP.getLangOptions());
}
+ // If there is a layout overrides file, attach an external AST source that
+ // provides the layouts from that file.
+ if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
+ CI.hasASTContext() && !CI.getASTContext().getExternalSource()) {
+ llvm::OwningPtr<ExternalASTSource>
+ Override(new LayoutOverrideSource(
+ CI.getFrontendOpts().OverrideRecordLayoutsFile));
+ CI.getASTContext().setExternalSource(Override);
+ }
+
return true;
// If we failed, reset state since the client will not end up calling the
--- /dev/null
+//===--- LayoutOverrideSource.cpp --Override Record Layouts ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Frontend/LayoutOverrideSource.h"
+#include "clang/AST/Decl.h"
+#include "llvm/Support/raw_ostream.h"
+#include <fstream>
+#include <string>
+
+using namespace clang;
+
+/// \brief Parse a simple identifier.
+std::string parseName(StringRef S) {
+ unsigned Offset = 0;
+ while (Offset < S.size() &&
+ (isalpha(S[Offset]) || S[Offset] == '_' ||
+ (Offset > 0 && isdigit(S[Offset]))))
+ ++Offset;
+
+ return S.substr(0, Offset).str();
+}
+
+LayoutOverrideSource::LayoutOverrideSource(llvm::StringRef Filename) {
+ std::ifstream Input(Filename.str().c_str());
+ if (!Input.is_open())
+ return;
+
+ // Parse the output of -fdump-record-layouts.
+ std::string CurrentType;
+ Layout CurrentLayout;
+ bool ExpectingType = false;
+
+ while (Input.good()) {
+ std::string Line;
+ getline(Input, Line);
+
+ StringRef LineStr(Line);
+
+ // Determine whether the following line will start a
+ if (LineStr.find("*** Dumping AST Record Layout") != StringRef::npos) {
+ // Flush the last type/layout, if there is one.
+ if (!CurrentType.empty())
+ Layouts[CurrentType] = CurrentLayout;
+ CurrentLayout = Layout();
+
+ ExpectingType = true;
+ continue;
+ }
+
+ // If we're expecting a type, grab it.
+ if (ExpectingType) {
+ ExpectingType = false;
+
+ StringRef::size_type Pos;
+ if ((Pos = LineStr.find("struct ")) != StringRef::npos)
+ LineStr = LineStr.substr(Pos + strlen("struct "));
+ else if ((Pos = LineStr.find("class ")) != StringRef::npos)
+ LineStr = LineStr.substr(Pos + strlen("class "));
+ else if ((Pos = LineStr.find("union ")) != StringRef::npos)
+ LineStr = LineStr.substr(Pos + strlen("union "));
+ else
+ continue;
+
+ // Find the name of the type.
+ CurrentType = parseName(LineStr);
+ CurrentLayout = Layout();
+ continue;
+ }
+
+ // Check for the size of the type.
+ StringRef::size_type Pos = LineStr.find("Size:");
+ if (Pos != StringRef::npos) {
+ // Skip past the "Size:" prefix.
+ LineStr = LineStr.substr(Pos + strlen("Size:"));
+
+ unsigned long long Size = 0;
+ (void)LineStr.getAsInteger(10, Size);
+ CurrentLayout.Size = Size;
+ continue;
+ }
+
+ // Check for the alignment of the type.
+ Pos = LineStr.find("Alignment:");
+ if (Pos != StringRef::npos) {
+ // Skip past the "Alignment:" prefix.
+ LineStr = LineStr.substr(Pos + strlen("Alignment:"));
+
+ unsigned long long Alignment = 0;
+ (void)LineStr.getAsInteger(10, Alignment);
+ CurrentLayout.Align = Alignment;
+ continue;
+ }
+
+ // Check for the size/alignment of the type.
+ Pos = LineStr.find("sizeof=");
+ if (Pos != StringRef::npos) {
+ /* Skip past the sizeof= prefix. */
+ LineStr = LineStr.substr(Pos + strlen("sizeof="));
+
+ // Parse size.
+ unsigned long long Size = 0;
+ (void)LineStr.getAsInteger(10, Size);
+ CurrentLayout.Size = Size;
+
+ Pos = LineStr.find("align=");
+ if (Pos != StringRef::npos) {
+ /* Skip past the align= prefix. */
+ LineStr = LineStr.substr(Pos + strlen("align="));
+
+ // Parse alignment.
+ unsigned long long Alignment = 0;
+ (void)LineStr.getAsInteger(10, Alignment);
+ CurrentLayout.Align = Alignment;
+ }
+
+ continue;
+ }
+
+ // Check for the field offsets of the type.
+ Pos = LineStr.find("FieldOffsets: [");
+ if (Pos == StringRef::npos)
+ continue;
+
+ LineStr = LineStr.substr(Pos + strlen("FieldOffsets: ["));
+ while (!LineStr.empty() && isdigit(LineStr[0])) {
+ // Parse this offset.
+ unsigned Idx = 1;
+ while (Idx < LineStr.size() && isdigit(LineStr[Idx]))
+ ++Idx;
+
+ unsigned long long Offset = 0;
+ (void)LineStr.substr(0, Idx).getAsInteger(10, Offset);
+
+ CurrentLayout.FieldOffsets.push_back(Offset);
+
+ // Skip over this offset, the following comma, and any spaces.
+ LineStr = LineStr.substr(Idx + 1);
+ while (!LineStr.empty() && isspace(LineStr[0]))
+ LineStr = LineStr.substr(1);
+ }
+ }
+
+ // Flush the last type/layout, if there is one.
+ if (!CurrentType.empty())
+ Layouts[CurrentType] = CurrentLayout;
+}
+
+bool
+LayoutOverrideSource::layoutRecordType(const RecordDecl *Record,
+ uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
+ llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets)
+{
+ // We can't override unnamed declarations.
+ if (!Record->getIdentifier())
+ return false;
+
+ // Check whether we have a layout for this record.
+ llvm::StringMap<Layout>::iterator Known = Layouts.find(Record->getName());
+ if (Known == Layouts.end())
+ return false;
+
+ // Provide field layouts.
+ unsigned NumFields = 0;
+ for (RecordDecl::field_iterator F = Record->field_begin(),
+ FEnd = Record->field_end();
+ F != FEnd; ++F, ++NumFields) {
+ if (NumFields >= Known->second.FieldOffsets.size())
+ continue;
+
+ FieldOffsets[*F] = Known->second.FieldOffsets[NumFields];
+ }
+
+ // Wrong number of fields.
+ if (NumFields != Known->second.FieldOffsets.size())
+ return false;
+
+ Size = Known->second.Size;
+ Alignment = Known->second.Align;
+ return true;
+}
+
+void LayoutOverrideSource::dump() {
+ llvm::raw_ostream &OS = llvm::errs();
+ for (llvm::StringMap<Layout>::iterator L = Layouts.begin(),
+ LEnd = Layouts.end();
+ L != LEnd; ++L) {
+ OS << "Type: blah " << L->first() << '\n';
+ OS << " Size:" << L->second.Size << '\n';
+ OS << " Alignment:" << L->second.Align << '\n';
+ OS << " FieldOffsets: [";
+ for (unsigned I = 0, N = L->second.FieldOffsets.size(); I != N; ++I) {
+ if (I)
+ OS << ", ";
+ OS << L->second.FieldOffsets[I];
+ }
+ OS << "]\n";
+ }
+}
+
--- /dev/null
+// RUN: %clang_cc1 -fdump-record-layouts %s 2> %t.layouts
+// RUN: %clang_cc1 -fdump-record-layouts-simple %s > %t.before 2>&1
+// RUN: %clang_cc1 -DPACKED= -DALIGNED16= -fdump-record-layouts-simple -foverride-record-layout=%t.layouts %s > %t.after 2>&1
+// RUN: diff %t.before %t.after
+// RUN: FileCheck %s < %t.after
+
+// If not explicitly disabled, set PACKED to the packed attribute.
+#ifndef PACKED
+# define PACKED __attribute__((packed))
+#endif
+
+// If not explicitly disabled, set ALIGNED16 to 16-byte alignment.
+#ifndef ALIGNED16
+# define ALIGNED16 __attribute__((aligned(16)))
+#endif
+
+// CHECK: Type: struct X0
+struct X0 {
+ int x[6] PACKED;
+};
+
+// CHECK: Type: struct X1
+struct X1 {
+ char x[13];
+ struct X0 y;
+} PACKED;
+
+// CHECK: Type: struct X2
+struct PACKED X2 {
+ short x;
+ int y;
+};
+
+// CHECK: Type: struct X3
+struct X3 {
+ short x PACKED;
+ int y;
+};
+
+#pragma pack(push,2)
+// CHECK: Type: struct X4
+struct X4 {
+ int x;
+ int y;
+};
+#pragma pack(pop)
+
+// CHECK: Type: struct X5
+struct PACKED X5 { double a[19]; signed char b; };
+
+// CHECK: Type: struct X6
+struct PACKED X6 { long double a; char b; };
+
+// CHECK: Type: struct X7
+typedef struct X7 {
+ unsigned x;
+ unsigned char y;
+} PACKED;
+
+// CHECK: Type: union X8
+union X8 {
+ struct X7 x;
+ unsigned y;
+} PACKED;
+
+// CHECK: Type: struct X9
+struct X9 {
+ unsigned int x[2] PACKED;
+ unsigned int y;
+ unsigned int z PACKED;
+};
+
+// CHECK: Type: struct X10
+struct X10 {
+ unsigned int x[2] PACKED;
+ unsigned int y PACKED;
+ unsigned int z PACKED;
+};
+
+// CHECK: Type: struct X11
+struct PACKED X11 {
+ unsigned int x[2];
+ unsigned int y;
+ unsigned int z;
+};
+
+// CHECK: Type: struct X12
+struct PACKED X12 {
+ int x : 24;
+};
+
+// CHECK: Type: struct X13
+struct PACKED X13 {
+ signed x : 10;
+ signed y : 10;
+};
+
+// CHECK: Type: union X14
+union PACKED X14 {
+ unsigned long long x : 3;
+};
+
+// CHECK: Type: struct X15
+struct X15 {
+ unsigned x : 16;
+ unsigned y : 28 PACKED;
+};
+
+// CHECK: Type: struct X16
+struct ALIGNED16 X16 {
+ int a, b, c;
+ int x : 5;
+ int y : 29;
+};
+
+void use_structs() {
+ struct X0 x0;
+ x0.x[5] = sizeof(struct X0);
+
+ struct X1 x1;
+ x1.x[5] = sizeof(struct X1);
+
+ struct X2 x2;
+ x2.y = sizeof(struct X2);
+
+ struct X3 x3;
+ x3.y = sizeof(struct X3);
+
+ struct X4 x4;
+ x4.y = sizeof(struct X4);
+
+ struct X5 x5;
+ x5.b = sizeof(struct X5);
+
+ struct X6 x6;
+ x6.b = sizeof(struct X6);
+
+ struct X7 x7;
+ x7.x = sizeof(struct X7);
+
+ union X8 x8;
+ x8.y = sizeof(union X8);
+
+ struct X9 x9;
+ x9.y = sizeof(struct X9);
+
+ struct X10 x10;
+ x10.y = sizeof(struct X10);
+
+ struct X11 x11;
+ x11.y = sizeof(struct X11);
+
+ struct X12 x12;
+ x12.x = sizeof(struct X12);
+
+ struct X13 x13;
+ x13.x = sizeof(struct X13);
+
+ union X14 x14;
+ x14.x = sizeof(union X14);
+
+ struct X15 x15;
+ x15.x = sizeof(struct X15);
+
+ struct X16 x16;
+ x16.x = sizeof(struct X16);
+}
--- /dev/null
+// RUN: %clang_cc1 -fdump-record-layouts-simple %s 2> %t.layouts
+// RUN: %clang_cc1 -fdump-record-layouts-simple %s > %t.before 2>&1
+// RUN: %clang_cc1 -DPACKED= -DALIGNED16= -fdump-record-layouts-simple -foverride-record-layout=%t.layouts %s > %t.after 2>&1
+// RUN: diff %t.before %t.after
+// RUN: FileCheck %s < %t.after
+
+// If not explicitly disabled, set PACKED to the packed attribute.
+#ifndef PACKED
+# define PACKED __attribute__((packed))
+#endif
+
+struct Empty1 { };
+struct Empty2 { };
+
+// CHECK: Type: struct X0
+struct X0 : public Empty1 {
+ int x[6] PACKED;
+};
+
+// CHECK: Type: struct X1
+struct X1 : public X0, public Empty2 {
+ char x[13];
+ struct X0 y;
+} PACKED;
+
+// CHECK: Type: struct X2
+struct PACKED X2 : public X1, public X0, public Empty1 {
+ short x;
+ int y;
+};
+
+// CHECK: Type: struct X3
+struct PACKED X3 : virtual public X1, public X0 {
+ short x;
+ int y;
+};
+
+void use_structs() {
+ struct X0 x0;
+ x0.x[5] = sizeof(struct X0);
+
+ struct X1 x1;
+ x1.x[5] = sizeof(struct X1);
+
+ struct X2 x2;
+ x2.y = sizeof(struct X2);
+
+ struct X3 x3;
+ x3.y = sizeof(struct X3);
+}