diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-01-26 07:55:45 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-01-26 07:55:45 +0000 |
commit | 453dbcbe30093fbf947a0bec2fbd46e9694eafe9 (patch) | |
tree | d7bdab4d63fe4983cf3a51b38621e9f37b696847 /lib | |
parent | 5b78a244ef213835337a5a860fe7c3f2fa90a943 (diff) |
Extend the ExternalASTSource interface to allow the AST source to
provide the layout of records, rather than letting Clang compute
the layout itself. LLDB provides the motivation for this feature:
because various layout-altering attributes (packed, aligned, etc.)
don't get reliably get placed into DWARF, the record layouts computed
by LLDB from the reconstructed records differ from the actual layouts,
and badness occurs. This interface lets the DWARF data drive layout,
so we don't need the attributes preserved to get the answer write.
The testing methodology for this change is fun. I've introduced a
variant of -fdump-record-layouts called -fdump-record-layouts-simple
that always has the simple C format and provides size/alignment/field
offsets. There is also a -cc1 option -foverride-record-layout=<file>
to take the output of -fdump-record-layouts-simple and parse it to
produce a set of overridden layouts, which is introduced into the AST
via a testing-only ExternalASTSource (called
LayoutOverrideSource). Each test contains a number of records to lay
out, which use various layout-changing attributes, and then dumps the
layouts. We then run the test again, using the preprocessor to
eliminate the layout-changing attributes entirely (which would give us
different layouts for the records), but supplying the
previously-computed record layouts. Finally, we diff the layouts
produced from the two runs to be sure that they are identical.
Note that this code makes the assumption that we don't *have* to
provide the offsets of bases or virtual bases to get the layout right,
because the alignment attributes don't affect it. I believe this
assumption holds, but if it does not, we can extend
LayoutOverrideSource to also provide base offset information.
Fixes the Clang side of <rdar://problem/10169539>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149055 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/RecordLayoutBuilder.cpp | 177 | ||||
-rw-r--r-- | lib/Frontend/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Frontend/CompilerInvocation.cpp | 13 | ||||
-rw-r--r-- | lib/Frontend/FrontendAction.cpp | 11 | ||||
-rw-r--r-- | lib/Frontend/LayoutOverrideSource.cpp | 206 |
5 files changed, 364 insertions, 44 deletions
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index d094461dc3..d6f3d5fea3 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -558,6 +558,10 @@ protected: 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; @@ -618,11 +622,26 @@ protected: /// 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()), @@ -1289,8 +1308,31 @@ void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) { 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())); @@ -1306,13 +1348,19 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { 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()); @@ -1355,6 +1403,23 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) { 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) { @@ -1647,6 +1712,12 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *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(), @@ -1707,16 +1778,19 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { 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. @@ -1729,8 +1803,9 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // 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) { @@ -1752,7 +1827,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { Context.toCharUnitsFromBits(UnpackedFieldAlign)); } -void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { +void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { if (D->isBitField()) { LayoutBitField(D); return; @@ -1769,6 +1844,13 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { 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. @@ -1846,25 +1928,33 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { 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); @@ -1936,8 +2026,9 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { 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) { @@ -2136,7 +2227,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { if (getLangOptions().DumpRecordLayouts) { llvm::errs() << "\n*** Dumping AST Record Layout\n"; - DumpRecordLayout(D, llvm::errs()); + DumpRecordLayout(D, llvm::errs(), getLangOptions().DumpRecordLayoutsSimple); } return *NewEntry; @@ -2329,16 +2420,20 @@ static void DumpCXXRecordLayout(raw_ostream &OS, } 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"; diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 40e813968a..1148bc4721 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -27,6 +27,7 @@ add_clang_library(clangFrontend InitHeaderSearch.cpp InitPreprocessor.cpp LangStandards.cpp + LayoutOverrideSource.cpp LogDiagnosticPrinter.cpp MultiplexConsumer.cpp PrintPreprocessedOutput.cpp diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 7e5af12d51..5a0117af5a 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -551,6 +551,8 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, 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, @@ -747,7 +749,9 @@ static void LangOptsToArgs(const LangOptions &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"); @@ -1410,7 +1414,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, 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, @@ -1863,7 +1868,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, 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); diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 42ba4d5a09..5a15847aea 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -18,6 +18,7 @@ #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" @@ -285,6 +286,16 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, 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 diff --git a/lib/Frontend/LayoutOverrideSource.cpp b/lib/Frontend/LayoutOverrideSource.cpp new file mode 100644 index 0000000000..3af2cc2bbe --- /dev/null +++ b/lib/Frontend/LayoutOverrideSource.cpp @@ -0,0 +1,206 @@ +//===--- 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"; + } +} + |