"git@repo.hca.bsc.es:rferrer/llvm-epi-0.8.git" did not exist on "647e61a42b797315bb40c71f5ec097a5e0e069ea"
Newer
Older
//=== RecordLayoutBuilder.cpp - Helper class for building 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/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/MathExtras.h"
#include <map>
using namespace clang;
/// BaseSubobjectInfo - Represents a single base subobject in a complete class.
/// For a class hierarchy like
///
/// class A { };
/// class B : A { };
/// class C : A, B { };
///
/// The BaseSubobjectInfo graph for C will have three BaseSubobjectInfo
/// instances, one for B and two for A.
///
/// If a base is virtual, it will only have one BaseSubobjectInfo allocated.
struct BaseSubobjectInfo {
/// Class - The class for this base info.
const CXXRecordDecl *Class;
/// IsVirtual - Whether the BaseInfo represents a virtual base or not.
/// Bases - Information about the base subobjects.
llvm::SmallVector<BaseSubobjectInfo*, 4> Bases;
/// PrimaryVirtualBaseInfo - Holds the base info for the primary virtual base
/// of this base info (if one exists).
BaseSubobjectInfo *PrimaryVirtualBaseInfo;
// FIXME: Document.
const BaseSubobjectInfo *Derived;
/// EmptySubobjectMap - Keeps track of which empty subobjects exist at different
/// offsets while laying out a C++ class.
class EmptySubobjectMap {
ASTContext &Context;
/// Class - The class whose empty entries we're keeping track of.
const CXXRecordDecl *Class;
/// EmptyClassOffsets - A map from offsets to empty record decls.
typedef llvm::SmallVector<const CXXRecordDecl *, 1> ClassVectorTy;
typedef llvm::DenseMap<CharUnits, ClassVectorTy> EmptyClassOffsetsMapTy;
EmptyClassOffsetsMapTy EmptyClassOffsets;
/// MaxEmptyClassOffset - The highest offset known to contain an empty
/// base subobject.
/// ComputeEmptySubobjectSizes - Compute the size of the largest base or
/// member subobject that is empty.
void ComputeEmptySubobjectSizes();
void AddSubobjectAtOffset(const CXXRecordDecl *RD, CharUnits Offset);
void UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
CharUnits Offset, bool PlacingEmptyBase);
void UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
CharUnits Offset);
void UpdateEmptyFieldSubobjects(const FieldDecl *FD, CharUnits Offset);
/// AnyEmptySubobjectsBeyondOffset - Returns whether there are any empty
/// subobjects beyond the given offset.
bool AnyEmptySubobjectsBeyondOffset(CharUnits Offset) const {
return Offset <= MaxEmptyClassOffset;
}
CharUnits
getFieldOffset(const ASTRecordLayout &Layout, unsigned FieldNo) const {
uint64_t FieldOffset = Layout.getFieldOffset(FieldNo);
assert(FieldOffset % CharWidth == 0 &&
"Field offset not at char boundary!");
return CharUnits::fromQuantity(FieldOffset / CharWidth);
}
// FIXME: Remove this.
CharUnits toCharUnits(uint64_t Offset) const {
return CharUnits::fromQuantity(Offset / CharWidth);
bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
CharUnits Offset) const;
bool CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
CharUnits Offset);
bool CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
CharUnits Offset) const;
bool CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
/// This holds the size of the largest empty subobject (either a base
/// or a member). Will be zero if the record being built doesn't contain
/// any empty classes.
CharUnits SizeOfLargestEmptySubobject;
EmptySubobjectMap(ASTContext &Context, const CXXRecordDecl *Class)
: Context(Context), CharWidth(Context.getCharWidth()), Class(Class) {
ComputeEmptySubobjectSizes();
}
/// CanPlaceBaseAtOffset - Return whether the given base class can be placed
/// at the given offset.
/// Returns false if placing the record will result in two components
/// (direct or indirect) of the same type having the same offset.
bool CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info,
CharUnits Offset);
/// CanPlaceFieldAtOffset - Return whether a field can be placed at the given
/// offset.
bool CanPlaceFieldAtOffset(const FieldDecl *FD, CharUnits Offset);
void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
// Check the bases.
for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
E = Class->bases_end(); I != E; ++I) {
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
CharUnits EmptySize;
const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
if (BaseDecl->isEmpty()) {
// If the class decl is empty, get its size.
EmptySize = toCharUnits(Layout.getSize());
} else {
// Otherwise, we get the largest empty subobject for the decl.
EmptySize = Layout.getSizeOfLargestEmptySubobject();
}
if (EmptySize > SizeOfLargestEmptySubobject)
SizeOfLargestEmptySubobject = EmptySize;
// Check the fields.
for (CXXRecordDecl::field_iterator I = Class->field_begin(),
E = Class->field_end(); I != E; ++I) {
const FieldDecl *FD = *I;
Context.getBaseElementType(FD->getType())->getAs<RecordType>();
// We only care about record types.
if (!RT)
continue;
CharUnits EmptySize;
const CXXRecordDecl *MemberDecl = cast<CXXRecordDecl>(RT->getDecl());
const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl);
if (MemberDecl->isEmpty()) {
// If the class decl is empty, get its size.
EmptySize = toCharUnits(Layout.getSize());
} else {
// Otherwise, we get the largest empty subobject for the decl.
EmptySize = Layout.getSizeOfLargestEmptySubobject();
}
if (EmptySize > SizeOfLargestEmptySubobject)
SizeOfLargestEmptySubobject = EmptySize;
bool
EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
// We only need to check empty bases.
if (!RD->isEmpty())
return true;
Loading
Loading full blame...