Add a new GetAddressOfBaseClass overload that takes a base path and. Use it for derived-to-base casts.

llvm-svn: 102270
This commit is contained in:
Anders Carlsson 2010-04-24 21:06:20 +00:00
parent c779e99540
commit d829a02514
3 changed files with 112 additions and 10 deletions

View File

@ -19,6 +19,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,
@ -132,6 +161,81 @@ ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr,
return 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,

View File

@ -840,15 +840,9 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
CXXRecordDecl *DerivedClassDecl =
cast<CXXRecordDecl>(DerivedClassTy->getDecl());
const RecordType *BaseClassTy =
DestTy->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseClassTy->getDecl());
Value *Src = Visit(const_cast<Expr*>(E));
bool NullCheckValue = ShouldNullCheckClassCastValue(CE);
return CGF.GetAddressOfBaseClass(Src, DerivedClassDecl, BaseClassDecl,
NullCheckValue);
return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl,
CE->getBasePath(),
ShouldNullCheckClassCastValue(CE));
}
case CastExpr::CK_Dynamic: {
Value *V = Visit(const_cast<Expr*>(E));

View File

@ -787,7 +787,11 @@ public:
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl,
bool NullCheckValue);
llvm::Value *GetAddressOfBaseClass(llvm::Value *Value,
const CXXRecordDecl *ClassDecl,
const CXXBaseSpecifierArray &BasePath,
bool NullCheckValue);
llvm::Value *GetAddressOfDerivedClass(llvm::Value *Value,
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *DerivedClassDecl,