From a8bbb82c55a3c8885b5cf23dd84f80b2a08c069a Mon Sep 17 00:00:00 2001 From: John McCall Date: Sun, 22 Aug 2010 03:04:22 +0000 Subject: [PATCH] Abstract out member-pointer conversions. Pretty much everything having to do with member pointers is ABI-specific. llvm-svn: 111770 --- clang/lib/CodeGen/CGCXX.cpp | 25 ++++++++++--- clang/lib/CodeGen/CGCXXABI.h | 7 ++++ clang/lib/CodeGen/CGExprAgg.cpp | 40 ++++---------------- clang/lib/CodeGen/ItaniumCXXABI.cpp | 57 +++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 38 deletions(-) diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index 7ae83f44b452..62c3954ee671 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -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(); @@ -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"); +} diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 7a89a3deac54..a28436b3e977 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -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. diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index bd7f18e24cc9..7b198bcf624d 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -322,39 +322,15 @@ 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(SrcType->getAs()-> - getClass()->getAs()->getDecl()); - const CXXRecordDecl *DerivedDecl = - cast(E->getType()->getAs()-> - getClass()->getAs()->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; } } diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 9ab7591ca2c4..9fc6be179dde 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -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(); + const MemberPointerType *DestTy = E->getType()->getAs(); + + 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); +}