[cfe-commits] r96070 - /cfe/trunk/lib/CodeGen/CGVtable.cpp
Anders Carlsson
andersca at mac.com
Fri Feb 12 18:02:03 PST 2010
Author: andersca
Date: Fri Feb 12 20:02:03 2010
New Revision: 96070
URL: http://llvm.org/viewvc/llvm-project?rev=96070&view=rev
Log:
More work on return type adjustments in the new vtable builder.
Modified:
cfe/trunk/lib/CodeGen/CGVtable.cpp
Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=96070&r1=96069&r2=96070&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVtable.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVtable.cpp Fri Feb 12 20:02:03 2010
@@ -121,16 +121,31 @@
/// member functions in the base subobjects of a class.
class FinalOverriders {
public:
+ /// BaseOffset - Represents an offset from a derived class to a direct or
+ /// indirect base class.
+ struct BaseOffset {
+ /// VirtualBase - If the path from the derived class to the base class
+ /// involves a virtual base class, this holds its declaration.
+ const CXXRecordDecl *VirtualBase;
+
+ /// NonVirtualOffset - The offset from the derived class to the base class.
+ /// Or the offset from the virtual base class to the base class, if the path
+ /// from the derived class to the base class involves a virtual base class.
+ uint64_t NonVirtualOffset;
+
+ BaseOffset() : VirtualBase(0), NonVirtualOffset(0) { }
+ BaseOffset(const CXXRecordDecl *VirtualBase, uint64_t NonVirtualOffset)
+ : VirtualBase(VirtualBase), NonVirtualOffset(NonVirtualOffset) { }
+
+ bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; };
+ };
+
/// OverriderInfo - Information about a final overrider.
struct OverriderInfo {
/// Method - The method decl of the overrider.
const CXXMethodDecl *Method;
- /// NeedsReturnAdjustment - Whether this overrider needs to adjust its
- /// return type.
- bool NeedsReturnAdjustment;
-
- OverriderInfo() : Method(0), NeedsReturnAdjustment(false) { }
+ OverriderInfo() : Method(0) { }
};
private:
@@ -143,13 +158,25 @@
/// MostDerivedClassLayout - the AST record layout of the most derived class.
const ASTRecordLayout &MostDerivedClassLayout;
- typedef llvm::DenseMap<std::pair<BaseSubobject, const CXXMethodDecl *>,
+ /// BaseSubobjectMethodPairTy - Uniquely identifies a member function
+ /// in a base subobject.
+ typedef std::pair<BaseSubobject, const CXXMethodDecl *>
+ BaseSubobjectMethodPairTy;
+
+ typedef llvm::DenseMap<BaseSubobjectMethodPairTy,
OverriderInfo> OverridersMapTy;
/// OverridersMap - The final overriders for all virtual member functions of
/// all the base subobjects of the most derived class.
OverridersMapTy OverridersMap;
+ typedef llvm::DenseMap<BaseSubobjectMethodPairTy, BaseOffset>
+ AdjustmentOffsetsMapTy;
+
+ /// ReturnAdjustments - Holds return adjustments for all the overriders that
+ /// need to perform return value adjustments.
+ AdjustmentOffsetsMapTy ReturnAdjustments;
+
typedef llvm::SmallVector<uint64_t, 1> OffsetVectorTy;
/// SubobjectOffsetsMapTy - This map is used for keeping track of all the
@@ -215,7 +242,7 @@
/// and indirect base subobjects.
void dump(llvm::raw_ostream &Out, BaseSubobject Base) const;
};
-
+
FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass)
: MostDerivedClass(MostDerivedClass),
Context(MostDerivedClass->getASTContext()),
@@ -251,6 +278,98 @@
}
}
+static FinalOverriders::BaseOffset
+ComputeBaseOffset(ASTContext &Context,
+ const CXXRecordDecl *DerivedRD,
+ const CXXRecordDecl *BaseRD) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/false,
+ /*RecordPaths=*/true, /*DetectVirtual=*/true);
+
+ if (!const_cast<CXXRecordDecl *>(DerivedRD)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
+ assert(false && "Class must be derived from the passed in base class!");
+ return FinalOverriders::BaseOffset();
+ }
+
+ assert(!Paths.getDetectedVirtual() &&
+ "FIXME: Handle virtual bases!");
+
+ uint64_t NonVirtualOffset = 0;
+
+ const CXXBasePath &Path = Paths.front();
+
+ for (size_t Start = 0, End = Path.size(); Start != End; ++Start) {
+ const CXXBasePathElement &Element = Path[Start];
+
+ // Check the base class offset.
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
+
+ const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
+ const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
+
+ NonVirtualOffset += Layout.getBaseClassOffset(Base);
+ }
+
+ // FIXME: This should probably use CharUnits or something. Maybe we should
+ // even change the base offsets in ASTRecordLayout to be specified in
+ // CharUnits.
+ return FinalOverriders::BaseOffset(0, NonVirtualOffset / 8);
+}
+
+static FinalOverriders::BaseOffset
+ComputeReturnTypeBaseOffset(ASTContext &Context,
+ const CXXMethodDecl *DerivedMD,
+ const CXXMethodDecl *BaseMD) {
+ const FunctionType *BaseFT = BaseMD->getType()->getAs<FunctionType>();
+ const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>();
+
+ // Canonicalize the return types.
+ CanQualType CanDerivedReturnType =
+ Context.getCanonicalType(DerivedFT->getResultType());
+ CanQualType CanBaseReturnType =
+ Context.getCanonicalType(BaseFT->getResultType());
+
+ assert(CanDerivedReturnType->getTypeClass() ==
+ CanBaseReturnType->getTypeClass() &&
+ "Types must have same type class!");
+
+ if (CanDerivedReturnType == CanBaseReturnType) {
+ // No adjustment needed.
+ return FinalOverriders::BaseOffset();
+ }
+
+ if (isa<ReferenceType>(CanDerivedReturnType)) {
+ CanDerivedReturnType =
+ CanDerivedReturnType->getAs<ReferenceType>()->getPointeeType();
+ CanBaseReturnType =
+ CanBaseReturnType->getAs<ReferenceType>()->getPointeeType();
+ } else if (isa<PointerType>(CanDerivedReturnType)) {
+ CanDerivedReturnType =
+ CanDerivedReturnType->getAs<PointerType>()->getPointeeType();
+ CanBaseReturnType =
+ CanBaseReturnType->getAs<PointerType>()->getPointeeType();
+ } else {
+ assert(false && "Unexpected return type!");
+ }
+
+ // We need to compare unqualified types here; consider
+ // const T *Base::foo();
+ // T *Derived::foo();
+ if (CanDerivedReturnType.getUnqualifiedType() ==
+ CanBaseReturnType.getUnqualifiedType()) {
+ // No adjustment needed.
+ return FinalOverriders::BaseOffset();
+ }
+
+ const CXXRecordDecl *DerivedRD =
+ cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl());
+
+ const CXXRecordDecl *BaseRD =
+ cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl());
+
+ return ComputeBaseOffset(Context, DerivedRD, BaseRD);
+}
+
void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD,
const CXXMethodDecl *NewMD,
SubobjectOffsetsMapTy &Offsets) {
@@ -273,25 +392,19 @@
for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) {
uint64_t Offset = OffsetVector[I];
- OverriderInfo &Overrider =
- OverridersMap[std::make_pair(BaseSubobject(OverriddenRD, Offset),
- OverriddenMD)];
+ BaseSubobjectMethodPairTy SubobjectAndMethod =
+ std::make_pair(BaseSubobject(OverriddenRD, Offset), OverriddenMD);
+
+ OverriderInfo &Overrider = OverridersMap[SubobjectAndMethod];
+
assert(Overrider.Method && "Did not find existing overrider!");
- /// We only need to do the return type check if the overrider doesn't
- /// already need a return adjustment. Consider:
- ///
- /// struct A { virtual V1 *f(); }
- /// struct B : A { virtual V2 *f(); }
- /// struct C : B { virtual V2 *f(); }
- ///
- /// If we assume that that V2->V1 needs an adjustment, then when we
- /// know that since A::f -> B::f needs an adjustment, then all classes
- /// that eventually override B::f (and by transitivity A::f) are going to
- /// need to have their return types adjusted.
- if (!Overrider.NeedsReturnAdjustment) {
- Overrider.NeedsReturnAdjustment =
- ReturnTypeConversionRequiresAdjustment(NewMD, OverriddenMD);
+ // Get the return adjustment base offset.
+ BaseOffset ReturnBaseOffset =
+ ComputeReturnTypeBaseOffset(Context, NewMD, OverriddenMD);
+ if (!ReturnBaseOffset.isEmpty()) {
+ // Store the return adjustment base offset.
+ ReturnAdjustments[SubobjectAndMethod] = ReturnBaseOffset;
}
// Set the new overrider.
@@ -388,8 +501,16 @@
Out << " " << MD->getQualifiedNameAsString() << " - ";
Out << Overrider.Method->getQualifiedNameAsString();
- if (Overrider.NeedsReturnAdjustment)
- Out << " [ret-adj]";
+
+ AdjustmentOffsetsMapTy::const_iterator I =
+ ReturnAdjustments.find(std::make_pair(Base, MD));
+ if (I != ReturnAdjustments.end()) {
+ const BaseOffset &Offset = I->second;
+
+ assert(!Offset.VirtualBase && "FIXME: Handle vbases!");
+
+ Out << " [ret-adj: " << Offset.NonVirtualOffset << " nv]";
+ }
Out << "\n";
}
}
@@ -627,9 +748,9 @@
// then we can just use the member function from the primary base.
if (const CXXMethodDecl *OverriddenMD =
OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
- assert(!ReturnTypeConversionRequiresAdjustment(MD, OverriddenMD)
+ assert(!ReturnTypeConversionRequiresAdjustment(MD, OverriddenMD)
&& "FIXME: Handle covariant thunks!");
-
+
continue;
}
@@ -2086,6 +2207,12 @@
const CXXRecordDecl *LayoutClass,
const CXXRecordDecl *RD, uint64_t Offset,
AddressPointsMapTy& AddressPoints) {
+ if (GenerateDefinition && CGM.getLangOptions().DumpVtableLayouts) {
+ VtableBuilder Builder(RD);
+
+ Builder.dumpLayout(llvm::errs());
+ }
+
llvm::SmallString<256> OutName;
if (LayoutClass != RD)
CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8,
@@ -2131,12 +2258,6 @@
}
}
- if (GenerateDefinition && CGM.getLangOptions().DumpVtableLayouts) {
- VtableBuilder Builder(RD);
-
- Builder.dumpLayout(llvm::errs());
- }
-
return GV;
}
More information about the cfe-commits
mailing list