aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGClass.cpp
diff options
context:
space:
mode:
authorAnders Carlsson <andersca@mac.com>2010-04-24 21:06:20 +0000
committerAnders Carlsson <andersca@mac.com>2010-04-24 21:06:20 +0000
commit34a2d384c745ebc39cae45dc1c0c4a6a7012e09b (patch)
tree56ff3f9462b1b8abb47c45c50c30d8aa7d2262ed /lib/CodeGen/CGClass.cpp
parentd1a272204cef9304df3930d94f66713b05db27d6 (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.cpp104
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,