[cfe-commits] r149055 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/ExternalASTSource.h include/clang/Basic/LangOptions.def include/clang/Driver/CC1Options.td include/clang/Frontend/FrontendOptions.h include/clang/Frontend/LayoutOverrideSource.h lib/AST/RecordLayoutBuilder.cpp lib/Frontend/CMakeLists.txt lib/Frontend/CompilerInvocation.cpp lib/Frontend/FrontendAction.cpp lib/Frontend/LayoutOverrideSource.cpp test/CodeGen/override-layout.c test/CodeGenCXX/override-layout.cpp

Douglas Gregor dgregor at apple.com
Wed Jan 25 23:55:46 PST 2012


Author: dgregor
Date: Thu Jan 26 01:55:45 2012
New Revision: 149055

URL: http://llvm.org/viewvc/llvm-project?rev=149055&view=rev
Log:
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>.


Added:
    cfe/trunk/include/clang/Frontend/LayoutOverrideSource.h   (with props)
    cfe/trunk/lib/Frontend/LayoutOverrideSource.cpp   (with props)
    cfe/trunk/test/CodeGen/override-layout.c   (with props)
    cfe/trunk/test/CodeGenCXX/override-layout.cpp   (with props)
Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/ExternalASTSource.h
    cfe/trunk/include/clang/Basic/LangOptions.def
    cfe/trunk/include/clang/Driver/CC1Options.td
    cfe/trunk/include/clang/Frontend/FrontendOptions.h
    cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
    cfe/trunk/lib/Frontend/CMakeLists.txt
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Frontend/FrontendAction.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=149055&r1=149054&r2=149055&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Thu Jan 26 01:55:45 2012
@@ -1300,7 +1300,8 @@
   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

Modified: cfe/trunk/include/clang/AST/ExternalASTSource.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExternalASTSource.h?rev=149055&r1=149054&r2=149055&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExternalASTSource.h (original)
+++ cfe/trunk/include/clang/AST/ExternalASTSource.h Thu Jan 26 01:55:45 2012
@@ -15,6 +15,8 @@
 #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 {
 
@@ -196,6 +198,44 @@
   /// 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.
   //===--------------------------------------------------------------------===//

Modified: cfe/trunk/include/clang/Basic/LangOptions.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.def?rev=149055&r1=149054&r2=149055&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.def (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.def Thu Jan 26 01:55:45 2012
@@ -117,6 +117,7 @@
 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")

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=149055&r1=149054&r2=149055&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Thu Jan 26 01:55:45 2012
@@ -451,6 +451,8 @@
   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">,
@@ -465,6 +467,9 @@
 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
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/include/clang/Frontend/FrontendOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendOptions.h?rev=149055&r1=149054&r2=149055&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendOptions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendOptions.h Thu Jan 26 01:55:45 2012
@@ -155,6 +155,10 @@
   /// 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;

Added: cfe/trunk/include/clang/Frontend/LayoutOverrideSource.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/LayoutOverrideSource.h?rev=149055&view=auto
==============================================================================
--- cfe/trunk/include/clang/Frontend/LayoutOverrideSource.h (added)
+++ cfe/trunk/include/clang/Frontend/LayoutOverrideSource.h Thu Jan 26 01:55:45 2012
@@ -0,0 +1,61 @@
+//===--- 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

Propchange: cfe/trunk/include/clang/Frontend/LayoutOverrideSource.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/include/clang/Frontend/LayoutOverrideSource.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/include/clang/Frontend/LayoutOverrideSource.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RecordLayoutBuilder.cpp?rev=149055&r1=149054&r2=149055&view=diff
==============================================================================
--- cfe/trunk/lib/AST/RecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/AST/RecordLayoutBuilder.cpp Thu Jan 26 01:55:45 2012
@@ -558,6 +558,10 @@
 
   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 @@
   /// 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 @@
 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 @@
     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 @@
     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 @@
   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 @@
     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 (FieldSize == 0 ||
-      (MaxFieldAlignment.isZero() &&
-       (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize))
-    UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
-                                                   UnpackedFieldAlign);
+  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);
+  }
 
   // Padding members don't affect overall alignment, unless zero length bitfield
   // alignment is enabled.
@@ -1729,8 +1803,9 @@
   // 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 @@
                   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 @@
   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 @@
     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::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 @@
 
   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 @@
 }
 
 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";

Modified: cfe/trunk/lib/Frontend/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CMakeLists.txt?rev=149055&r1=149054&r2=149055&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CMakeLists.txt (original)
+++ cfe/trunk/lib/Frontend/CMakeLists.txt Thu Jan 26 01:55:45 2012
@@ -27,6 +27,7 @@
   InitHeaderSearch.cpp
   InitPreprocessor.cpp
   LangStandards.cpp
+  LayoutOverrideSource.cpp
   LogDiagnosticPrinter.cpp
   MultiplexConsumer.cpp
   PrintPreprocessedOutput.cpp

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=149055&r1=149054&r2=149055&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Thu Jan 26 01:55:45 2012
@@ -551,6 +551,8 @@
     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 @@
     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 @@
   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 @@
   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);

Modified: cfe/trunk/lib/Frontend/FrontendAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendAction.cpp?rev=149055&r1=149054&r2=149055&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/FrontendAction.cpp (original)
+++ cfe/trunk/lib/Frontend/FrontendAction.cpp Thu Jan 26 01:55:45 2012
@@ -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 @@
                                            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

Added: cfe/trunk/lib/Frontend/LayoutOverrideSource.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/LayoutOverrideSource.cpp?rev=149055&view=auto
==============================================================================
--- cfe/trunk/lib/Frontend/LayoutOverrideSource.cpp (added)
+++ cfe/trunk/lib/Frontend/LayoutOverrideSource.cpp Thu Jan 26 01:55:45 2012
@@ -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";
+  }
+}
+

Propchange: cfe/trunk/lib/Frontend/LayoutOverrideSource.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/lib/Frontend/LayoutOverrideSource.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/lib/Frontend/LayoutOverrideSource.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/CodeGen/override-layout.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/override-layout.c?rev=149055&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/override-layout.c (added)
+++ cfe/trunk/test/CodeGen/override-layout.c Thu Jan 26 01:55:45 2012
@@ -0,0 +1,167 @@
+// 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);
+}

Propchange: cfe/trunk/test/CodeGen/override-layout.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CodeGen/override-layout.c
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CodeGen/override-layout.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/CodeGenCXX/override-layout.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/override-layout.cpp?rev=149055&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/override-layout.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/override-layout.cpp Thu Jan 26 01:55:45 2012
@@ -0,0 +1,50 @@
+// 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);
+}

Propchange: cfe/trunk/test/CodeGenCXX/override-layout.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CodeGenCXX/override-layout.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CodeGenCXX/override-layout.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list