Abstract out member-pointer conversions.

Pretty much everything having to do with member pointers is ABI-specific.

llvm-svn: 111770
This commit is contained in:
John McCall 2010-08-22 03:04:22 +00:00
parent 2807d4a58b
commit a8bbb82c55
4 changed files with 91 additions and 38 deletions

View File

@ -358,16 +358,21 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
CGCXXABI::~CGCXXABI() {}
static void ErrorUnsupportedABI(CodeGenFunction &CGF,
llvm::StringRef S) {
Diagnostic &Diags = CGF.CGM.getDiags();
unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
"cannot yet compile %s in this ABI");
Diags.Report(CGF.getContext().getFullLoc(CGF.CurCodeDecl->getLocation()),
DiagID)
<< S;
}
llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
llvm::Value *&This,
llvm::Value *MemPtr,
const MemberPointerType *MPT) {
Diagnostic &Diags = CGF.CGM.getDiags();
unsigned DiagID =
Diags.getCustomDiagID(Diagnostic::Error,
"cannot yet compile member pointer calls in this ABI");
Diags.Report(CGF.getContext().getFullLoc(CGF.CurCodeDecl->getLocation()),
DiagID);
ErrorUnsupportedABI(CGF, "calls through member pointers");
const FunctionProtoType *FPT =
MPT->getPointeeType()->getAs<FunctionProtoType>();
@ -379,3 +384,11 @@ llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
FPT->isVariadic());
return llvm::Constant::getNullValue(FTy->getPointerTo());
}
void CGCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
llvm::Value *Src,
llvm::Value *Dest,
bool VolatileDest) {
ErrorUnsupportedABI(CGF, "member pointer conversions");
}

View File

@ -20,6 +20,7 @@ namespace llvm {
}
namespace clang {
class CastExpr;
class MemberPointerType;
namespace CodeGen {
@ -40,6 +41,12 @@ public:
llvm::Value *&This,
llvm::Value *MemPtr,
const MemberPointerType *MPT);
virtual void EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
llvm::Value *Src,
llvm::Value *Dest,
bool VolatileDest);
};
/// Creates an instance of a C++ ABI class.

View File

@ -323,38 +323,14 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
llvm::Value *Src = CGF.CreateMemTemp(SrcType, "tmp");
CGF.EmitAggExpr(E->getSubExpr(), Src, SrcType.isVolatileQualified());
llvm::Value *SrcPtr = Builder.CreateStructGEP(Src, 0, "src.ptr");
SrcPtr = Builder.CreateLoad(SrcPtr);
llvm::Value *SrcAdj = Builder.CreateStructGEP(Src, 1, "src.adj");
SrcAdj = Builder.CreateLoad(SrcAdj);
llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr");
Builder.CreateStore(SrcPtr, DstPtr, VolatileDest);
llvm::Value *DstAdj = Builder.CreateStructGEP(DestPtr, 1, "dst.adj");
// Now See if we need to update the adjustment.
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(SrcType->getAs<MemberPointerType>()->
getClass()->getAs<RecordType>()->getDecl());
const CXXRecordDecl *DerivedDecl =
cast<CXXRecordDecl>(E->getType()->getAs<MemberPointerType>()->
getClass()->getAs<RecordType>()->getDecl());
if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
std::swap(DerivedDecl, BaseDecl);
if (llvm::Constant *Adj =
CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl,
E->path_begin(),
E->path_end())) {
if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj");
else
SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj");
}
Builder.CreateStore(SrcAdj, DstAdj, VolatileDest);
// Note that the AST doesn't distinguish between checked and
// unchecked member pointer conversions, so we always have to
// implement checked conversions here. This is inefficient for
// ABIs where an actual null check is thus required; fortunately,
// the Itanium and ARM ABIs ignore the adjustment value when
// considering null-ness.
CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, E, Src,
DestPtr, VolatileDest);
break;
}
}

View File

@ -46,6 +46,12 @@ public:
llvm::Value *&This,
llvm::Value *MemFnPtr,
const MemberPointerType *MPT);
void EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
llvm::Value *Src,
llvm::Value *Dest,
bool VolatileDest);
};
class ARMCXXABI : public ItaniumCXXABI {
@ -168,3 +174,54 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
Callee->addIncoming(NonVirtualFn, FnNonVirtual);
return Callee;
}
/// Perform a derived-to-base or base-to-derived member pointer conversion.
void ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
llvm::Value *Src,
llvm::Value *Dest,
bool VolatileDest) {
assert(E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer ||
E->getCastKind() == CastExpr::CK_BaseToDerivedMemberPointer);
CGBuilderTy &Builder = CGF.Builder;
const MemberPointerType *SrcTy =
E->getSubExpr()->getType()->getAs<MemberPointerType>();
const MemberPointerType *DestTy = E->getType()->getAs<MemberPointerType>();
const CXXRecordDecl *SrcDecl = SrcTy->getClass()->getAsCXXRecordDecl();
const CXXRecordDecl *DestDecl = DestTy->getClass()->getAsCXXRecordDecl();
llvm::Value *SrcPtr = Builder.CreateStructGEP(Src, 0, "src.ptr");
SrcPtr = Builder.CreateLoad(SrcPtr);
llvm::Value *SrcAdj = Builder.CreateStructGEP(Src, 1, "src.adj");
SrcAdj = Builder.CreateLoad(SrcAdj);
llvm::Value *DstPtr = Builder.CreateStructGEP(Dest, 0, "dst.ptr");
Builder.CreateStore(SrcPtr, DstPtr, VolatileDest);
llvm::Value *DstAdj = Builder.CreateStructGEP(Dest, 1, "dst.adj");
bool DerivedToBase =
E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer;
const CXXRecordDecl *BaseDecl, *DerivedDecl;
if (DerivedToBase)
DerivedDecl = SrcDecl, BaseDecl = DestDecl;
else
BaseDecl = SrcDecl, DerivedDecl = DestDecl;
if (llvm::Constant *Adj =
CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl,
E->path_begin(),
E->path_end())) {
if (DerivedToBase)
SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj");
else
SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj");
}
Builder.CreateStore(SrcAdj, DstAdj, VolatileDest);
}