diff options
author | Anders Carlsson <andersca@mac.com> | 2010-04-24 21:06:20 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2010-04-24 21:06:20 +0000 |
commit | 34a2d384c745ebc39cae45dc1c0c4a6a7012e09b (patch) | |
tree | 56ff3f9462b1b8abb47c45c50c30d8aa7d2262ed /lib/CodeGen/CGClass.cpp | |
parent | d1a272204cef9304df3930d94f66713b05db27d6 (diff) |
Add a new GetAddressOfBaseClass overload that takes a base path and. Use it for derived-to-base casts.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102270 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGClass.cpp')
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 2b06e5e41d..991b6a71d3 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -20,6 +20,35 @@ using namespace clang; using namespace CodeGen; static uint64_t +ComputeNonVirtualBaseClassOffset(ASTContext &Context, + const CXXRecordDecl *DerivedClass, + CXXBaseSpecifierArray::iterator Start, + CXXBaseSpecifierArray::iterator End) { + uint64_t Offset = 0; + + const CXXRecordDecl *RD = DerivedClass; + + for (CXXBaseSpecifierArray::iterator I = Start; I != End; ++I) { + const CXXBaseSpecifier *Base = *I; + assert(!Base->isVirtual() && "Should not see virtual bases here!"); + + // Get the layout. + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + + // Add the offset. + Offset += Layout.getBaseClassOffset(BaseDecl); + + RD = BaseDecl; + } + + // FIXME: We should not use / 8 here. + return Offset / 8; +} + +static uint64_t ComputeNonVirtualBaseClassOffset(ASTContext &Context, const CXXBasePath &Path, unsigned Start) { @@ -133,6 +162,81 @@ ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr, } llvm::Value * +CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, + const CXXRecordDecl *ClassDecl, + const CXXBaseSpecifierArray &BasePath, + bool NullCheckValue) { + assert(!BasePath.empty() && "Base path should not be empty!"); + + CXXBaseSpecifierArray::iterator Start = BasePath.begin(); + const CXXRecordDecl *VBase = 0; + + // Get the virtual base. + if ((*Start)->isVirtual()) { + VBase = + cast<CXXRecordDecl>((*Start)->getType()->getAs<RecordType>()->getDecl()); + ++Start; + } + + uint64_t NonVirtualOffset = + ComputeNonVirtualBaseClassOffset(getContext(), VBase ? VBase : ClassDecl, + Start, BasePath.end()); + + // Get the base pointer type. + const llvm::Type *BasePtrTy = + llvm::PointerType::getUnqual(ConvertType((BasePath.end()[-1])->getType())); + + if (!NonVirtualOffset && !VBase) { + // Just cast back. + return Builder.CreateBitCast(Value, BasePtrTy); + } + + llvm::BasicBlock *CastNull = 0; + llvm::BasicBlock *CastNotNull = 0; + llvm::BasicBlock *CastEnd = 0; + + if (NullCheckValue) { + CastNull = createBasicBlock("cast.null"); + CastNotNull = createBasicBlock("cast.notnull"); + CastEnd = createBasicBlock("cast.end"); + + llvm::Value *IsNull = + Builder.CreateICmpEQ(Value, + llvm::Constant::getNullValue(Value->getType())); + Builder.CreateCondBr(IsNull, CastNull, CastNotNull); + EmitBlock(CastNotNull); + } + + llvm::Value *VirtualOffset = 0; + + if (VBase) + VirtualOffset = GetVirtualBaseClassOffset(Value, ClassDecl, VBase); + + // Apply the offsets. + Value = ApplyNonVirtualAndVirtualOffset(*this, Value, NonVirtualOffset, + VirtualOffset); + + // Cast back. + Value = Builder.CreateBitCast(Value, BasePtrTy); + + if (NullCheckValue) { + Builder.CreateBr(CastEnd); + EmitBlock(CastNull); + Builder.CreateBr(CastEnd); + EmitBlock(CastEnd); + + llvm::PHINode *PHI = Builder.CreatePHI(Value->getType()); + PHI->reserveOperandSpace(2); + PHI->addIncoming(Value, CastNotNull); + PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), + CastNull); + Value = PHI; + } + + return Value; +} + +llvm::Value * CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, const CXXRecordDecl *Class, const CXXRecordDecl *BaseClass, |