Handle base-to-derived casts. Will land test case shortly.
llvm-svn: 89678
This commit is contained in:
parent
d976d3e552
commit
8c793172c2
|
@ -1211,10 +1211,10 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
|
||||||
const CXXRecordDecl *ClassDecl,
|
const CXXRecordDecl *ClassDecl,
|
||||||
const CXXRecordDecl *BaseClassDecl, QualType Ty) {
|
const CXXRecordDecl *BaseClassDecl, QualType Ty) {
|
||||||
if (ClassDecl) {
|
if (ClassDecl) {
|
||||||
Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl,
|
Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
|
||||||
/*NullCheckValue=*/false);
|
/*NullCheckValue=*/false);
|
||||||
Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl,
|
Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
|
||||||
/*NullCheckValue=*/false);
|
/*NullCheckValue=*/false);
|
||||||
}
|
}
|
||||||
if (BaseClassDecl->hasTrivialCopyConstructor()) {
|
if (BaseClassDecl->hasTrivialCopyConstructor()) {
|
||||||
EmitAggregateCopy(Dest, Src, Ty);
|
EmitAggregateCopy(Dest, Src, Ty);
|
||||||
|
@ -1250,10 +1250,10 @@ void CodeGenFunction::EmitClassCopyAssignment(
|
||||||
const CXXRecordDecl *BaseClassDecl,
|
const CXXRecordDecl *BaseClassDecl,
|
||||||
QualType Ty) {
|
QualType Ty) {
|
||||||
if (ClassDecl) {
|
if (ClassDecl) {
|
||||||
Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl,
|
Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
|
||||||
/*NullCheckValue=*/false);
|
/*NullCheckValue=*/false);
|
||||||
Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl,
|
Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
|
||||||
/*NullCheckValue=*/false);
|
/*NullCheckValue=*/false);
|
||||||
}
|
}
|
||||||
if (BaseClassDecl->hasTrivialCopyAssignment()) {
|
if (BaseClassDecl->hasTrivialCopyAssignment()) {
|
||||||
EmitAggregateCopy(Dest, Src, Ty);
|
EmitAggregateCopy(Dest, Src, Ty);
|
||||||
|
@ -1493,9 +1493,9 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
|
||||||
const Type *BaseType = BaseInit->getBaseClass();
|
const Type *BaseType = BaseInit->getBaseClass();
|
||||||
CXXRecordDecl *BaseClassDecl =
|
CXXRecordDecl *BaseClassDecl =
|
||||||
cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
|
cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
|
||||||
llvm::Value *V = CGF.GetAddressCXXOfBaseClass(ThisPtr, ClassDecl,
|
llvm::Value *V = CGF.GetAddressOfBaseClass(ThisPtr, ClassDecl,
|
||||||
BaseClassDecl,
|
BaseClassDecl,
|
||||||
/*NullCheckValue=*/false);
|
/*NullCheckValue=*/false);
|
||||||
CGF.EmitCXXConstructorCall(BaseInit->getConstructor(),
|
CGF.EmitCXXConstructorCall(BaseInit->getConstructor(),
|
||||||
CtorType, V,
|
CtorType, V,
|
||||||
BaseInit->const_arg_begin(),
|
BaseInit->const_arg_begin(),
|
||||||
|
@ -1710,9 +1710,9 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
|
||||||
if (BaseClassDecl->hasTrivialDestructor())
|
if (BaseClassDecl->hasTrivialDestructor())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(),
|
llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
|
||||||
ClassDecl, BaseClassDecl,
|
ClassDecl, BaseClassDecl,
|
||||||
/*NullCheckValue=*/false);
|
/*NullCheckValue=*/false);
|
||||||
EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
|
EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
|
||||||
Dtor_Base, V);
|
Dtor_Base, V);
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,10 +117,10 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value *
|
llvm::Value *
|
||||||
CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
|
CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
|
||||||
const CXXRecordDecl *ClassDecl,
|
const CXXRecordDecl *ClassDecl,
|
||||||
const CXXRecordDecl *BaseClassDecl,
|
const CXXRecordDecl *BaseClassDecl,
|
||||||
bool NullCheckValue) {
|
bool NullCheckValue) {
|
||||||
QualType BTy =
|
QualType BTy =
|
||||||
getContext().getCanonicalType(
|
getContext().getCanonicalType(
|
||||||
getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
|
getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
|
||||||
|
@ -128,7 +128,7 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
|
||||||
|
|
||||||
if (ClassDecl == BaseClassDecl) {
|
if (ClassDecl == BaseClassDecl) {
|
||||||
// Just cast back.
|
// Just cast back.
|
||||||
return Builder.CreateBitCast(BaseValue, BasePtrTy);
|
return Builder.CreateBitCast(Value, BasePtrTy);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::BasicBlock *CastNull = 0;
|
llvm::BasicBlock *CastNull = 0;
|
||||||
|
@ -141,8 +141,8 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
|
||||||
CastEnd = createBasicBlock("cast.end");
|
CastEnd = createBasicBlock("cast.end");
|
||||||
|
|
||||||
llvm::Value *IsNull =
|
llvm::Value *IsNull =
|
||||||
Builder.CreateICmpEQ(BaseValue,
|
Builder.CreateICmpEQ(Value,
|
||||||
llvm::Constant::getNullValue(BaseValue->getType()));
|
llvm::Constant::getNullValue(Value->getType()));
|
||||||
Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
|
Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
|
||||||
EmitBlock(CastNotNull);
|
EmitBlock(CastNotNull);
|
||||||
}
|
}
|
||||||
|
@ -150,16 +150,16 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
|
||||||
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
|
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
|
||||||
|
|
||||||
llvm::Value *Offset =
|
llvm::Value *Offset =
|
||||||
GetCXXBaseClassOffset(*this, BaseValue, ClassDecl, BaseClassDecl);
|
GetCXXBaseClassOffset(*this, Value, ClassDecl, BaseClassDecl);
|
||||||
|
|
||||||
if (Offset) {
|
if (Offset) {
|
||||||
// Apply the offset.
|
// Apply the offset.
|
||||||
BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy);
|
Value = Builder.CreateBitCast(Value, Int8PtrTy);
|
||||||
BaseValue = Builder.CreateGEP(BaseValue, Offset, "add.ptr");
|
Value = Builder.CreateGEP(Value, Offset, "add.ptr");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cast back.
|
// Cast back.
|
||||||
BaseValue = Builder.CreateBitCast(BaseValue, BasePtrTy);
|
Value = Builder.CreateBitCast(Value, BasePtrTy);
|
||||||
|
|
||||||
if (NullCheckValue) {
|
if (NullCheckValue) {
|
||||||
Builder.CreateBr(CastEnd);
|
Builder.CreateBr(CastEnd);
|
||||||
|
@ -167,13 +167,73 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
|
||||||
Builder.CreateBr(CastEnd);
|
Builder.CreateBr(CastEnd);
|
||||||
EmitBlock(CastEnd);
|
EmitBlock(CastEnd);
|
||||||
|
|
||||||
llvm::PHINode *PHI = Builder.CreatePHI(BaseValue->getType());
|
llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
|
||||||
PHI->reserveOperandSpace(2);
|
PHI->reserveOperandSpace(2);
|
||||||
PHI->addIncoming(BaseValue, CastNotNull);
|
PHI->addIncoming(Value, CastNotNull);
|
||||||
PHI->addIncoming(llvm::Constant::getNullValue(BaseValue->getType()),
|
PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
|
||||||
CastNull);
|
CastNull);
|
||||||
BaseValue = PHI;
|
Value = PHI;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BaseValue;
|
return Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value *
|
||||||
|
CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
|
||||||
|
const CXXRecordDecl *ClassDecl,
|
||||||
|
const CXXRecordDecl *DerivedClassDecl,
|
||||||
|
bool NullCheckValue) {
|
||||||
|
QualType DerivedTy =
|
||||||
|
getContext().getCanonicalType(
|
||||||
|
getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClassDecl)));
|
||||||
|
const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
|
||||||
|
|
||||||
|
if (ClassDecl == DerivedClassDecl) {
|
||||||
|
// Just cast back.
|
||||||
|
return Builder.CreateBitCast(Value, DerivedPtrTy);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 *Offset = GetCXXBaseClassOffset(*this, Value, DerivedClassDecl,
|
||||||
|
ClassDecl);
|
||||||
|
if (Offset) {
|
||||||
|
// Apply the offset.
|
||||||
|
Value = Builder.CreatePtrToInt(Value, Offset->getType());
|
||||||
|
Value = Builder.CreateSub(Value, Offset);
|
||||||
|
Value = Builder.CreateIntToPtr(Value, DerivedPtrTy);
|
||||||
|
} else {
|
||||||
|
// Just cast.
|
||||||
|
Value = Builder.CreateBitCast(Value, DerivedPtrTy);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,8 +148,8 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
|
||||||
if (BaseClassDecl) {
|
if (BaseClassDecl) {
|
||||||
llvm::Value *Derived = Val.getAggregateAddr();
|
llvm::Value *Derived = Val.getAggregateAddr();
|
||||||
llvm::Value *Base =
|
llvm::Value *Base =
|
||||||
GetAddressCXXOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl,
|
GetAddressOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl,
|
||||||
/*NullCheckValue=*/false);
|
/*NullCheckValue=*/false);
|
||||||
return RValue::get(Base);
|
return RValue::get(Base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1328,8 +1328,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
|
||||||
|
|
||||||
// Perform the derived-to-base conversion
|
// Perform the derived-to-base conversion
|
||||||
llvm::Value *Base =
|
llvm::Value *Base =
|
||||||
GetAddressCXXOfBaseClass(LV.getAddress(), DerivedClassDecl,
|
GetAddressOfBaseClass(LV.getAddress(), DerivedClassDecl,
|
||||||
BaseClassDecl, /*NullCheckValue=*/false);
|
BaseClassDecl, /*NullCheckValue=*/false);
|
||||||
|
|
||||||
return LValue::MakeAddr(Base, MakeQualifiers(E->getType()));
|
return LValue::MakeAddr(Base, MakeQualifiers(E->getType()));
|
||||||
}
|
}
|
||||||
|
@ -1340,7 +1340,23 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
|
||||||
return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
|
return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
|
||||||
}
|
}
|
||||||
case CastExpr::CK_BaseToDerived: {
|
case CastExpr::CK_BaseToDerived: {
|
||||||
return EmitUnsupportedLValue(E, "base-to-derived cast lvalue");
|
const RecordType *BaseClassTy =
|
||||||
|
E->getSubExpr()->getType()->getAs<RecordType>();
|
||||||
|
CXXRecordDecl *BaseClassDecl =
|
||||||
|
cast<CXXRecordDecl>(BaseClassTy->getDecl());
|
||||||
|
|
||||||
|
const RecordType *DerivedClassTy = E->getType()->getAs<RecordType>();
|
||||||
|
CXXRecordDecl *DerivedClassDecl =
|
||||||
|
cast<CXXRecordDecl>(DerivedClassTy->getDecl());
|
||||||
|
|
||||||
|
LValue LV = EmitLValue(E->getSubExpr());
|
||||||
|
|
||||||
|
// Perform the base-to-derived conversion
|
||||||
|
llvm::Value *Derived =
|
||||||
|
GetAddressOfDerivedClass(LV.getAddress(), BaseClassDecl,
|
||||||
|
DerivedClassDecl, /*NullCheckValue=*/false);
|
||||||
|
|
||||||
|
return LValue::MakeAddr(Derived, MakeQualifiers(E->getType()));
|
||||||
}
|
}
|
||||||
case CastExpr::CK_BitCast: {
|
case CastExpr::CK_BitCast: {
|
||||||
// This must be a reinterpret_cast (or c-style equivalent).
|
// This must be a reinterpret_cast (or c-style equivalent).
|
||||||
|
|
|
@ -748,6 +748,23 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
|
||||||
return V;
|
return V;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ShouldNullCheckClassCastValue(const CastExpr *CE) {
|
||||||
|
const Expr *E = CE->getSubExpr();
|
||||||
|
|
||||||
|
if (isa<CXXThisExpr>(E)) {
|
||||||
|
// We always assume that 'this' is never null.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
|
||||||
|
// And that lvalue casts are never null.
|
||||||
|
if (ICE->isLvalueCast())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts
|
// VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts
|
||||||
// have to handle a more broad range of conversions than explicit casts, as they
|
// have to handle a more broad range of conversions than explicit casts, as they
|
||||||
// handle things like function to ptr-to-function decay etc.
|
// handle things like function to ptr-to-function decay etc.
|
||||||
|
@ -775,6 +792,19 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
|
||||||
case CastExpr::CK_NoOp:
|
case CastExpr::CK_NoOp:
|
||||||
return Visit(const_cast<Expr*>(E));
|
return Visit(const_cast<Expr*>(E));
|
||||||
|
|
||||||
|
case CastExpr::CK_BaseToDerived: {
|
||||||
|
const CXXRecordDecl *BaseClassDecl =
|
||||||
|
E->getType()->getCXXRecordDeclForPointerType();
|
||||||
|
const CXXRecordDecl *DerivedClassDecl =
|
||||||
|
DestTy->getCXXRecordDeclForPointerType();
|
||||||
|
|
||||||
|
Value *Src = Visit(const_cast<Expr*>(E));
|
||||||
|
|
||||||
|
bool NullCheckValue = ShouldNullCheckClassCastValue(CE);
|
||||||
|
return CGF.GetAddressOfDerivedClass(Src, BaseClassDecl, DerivedClassDecl,
|
||||||
|
NullCheckValue);
|
||||||
|
}
|
||||||
|
|
||||||
case CastExpr::CK_DerivedToBase: {
|
case CastExpr::CK_DerivedToBase: {
|
||||||
const RecordType *DerivedClassTy =
|
const RecordType *DerivedClassTy =
|
||||||
E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
|
E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
|
||||||
|
@ -787,18 +817,9 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
|
||||||
|
|
||||||
Value *Src = Visit(const_cast<Expr*>(E));
|
Value *Src = Visit(const_cast<Expr*>(E));
|
||||||
|
|
||||||
bool NullCheckValue = true;
|
bool NullCheckValue = ShouldNullCheckClassCastValue(CE);
|
||||||
|
return CGF.GetAddressOfBaseClass(Src, DerivedClassDecl, BaseClassDecl,
|
||||||
if (isa<CXXThisExpr>(E)) {
|
NullCheckValue);
|
||||||
// We always assume that 'this' is never null.
|
|
||||||
NullCheckValue = false;
|
|
||||||
} else if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
|
|
||||||
// And that lvalue casts are never null.
|
|
||||||
if (ICE->isLvalueCast())
|
|
||||||
NullCheckValue = false;
|
|
||||||
}
|
|
||||||
return CGF.GetAddressCXXOfBaseClass(Src, DerivedClassDecl, BaseClassDecl,
|
|
||||||
NullCheckValue);
|
|
||||||
}
|
}
|
||||||
case CastExpr::CK_ToUnion: {
|
case CastExpr::CK_ToUnion: {
|
||||||
assert(0 && "Should be unreachable!");
|
assert(0 && "Should be unreachable!");
|
||||||
|
|
|
@ -598,15 +598,20 @@ public:
|
||||||
/// generating code for an C++ member function.
|
/// generating code for an C++ member function.
|
||||||
llvm::Value *LoadCXXThis();
|
llvm::Value *LoadCXXThis();
|
||||||
|
|
||||||
/// GetAddressCXXOfBaseClass - This function will add the necessary delta
|
/// GetAddressOfBaseClass - This function will add the necessary delta
|
||||||
/// to the load of 'this' and returns address of the base class.
|
/// to the load of 'this' and returns address of the base class.
|
||||||
// FIXME. This currently only does a derived to non-virtual base conversion.
|
// FIXME. This currently only does a derived to non-virtual base conversion.
|
||||||
// Other kinds of conversions will come later.
|
// Other kinds of conversions will come later.
|
||||||
llvm::Value *GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
|
llvm::Value *GetAddressOfBaseClass(llvm::Value *Value,
|
||||||
const CXXRecordDecl *ClassDecl,
|
const CXXRecordDecl *ClassDecl,
|
||||||
const CXXRecordDecl *BaseClassDecl,
|
const CXXRecordDecl *BaseClassDecl,
|
||||||
bool NullCheckValue);
|
bool NullCheckValue);
|
||||||
|
|
||||||
|
llvm::Value *GetAddressOfDerivedClass(llvm::Value *Value,
|
||||||
|
const CXXRecordDecl *ClassDecl,
|
||||||
|
const CXXRecordDecl *DerivedClassDecl,
|
||||||
|
bool NullCheckValue);
|
||||||
|
|
||||||
llvm::Value *
|
llvm::Value *
|
||||||
GetVirtualCXXBaseClassOffset(llvm::Value *This,
|
GetVirtualCXXBaseClassOffset(llvm::Value *This,
|
||||||
const CXXRecordDecl *ClassDecl,
|
const CXXRecordDecl *ClassDecl,
|
||||||
|
|
Loading…
Reference in New Issue