diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-03-03 17:28:16 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-03-03 17:28:16 +0000 |
commit | df90325d4c0a65ee64d2dae3ed9b5b34f7418533 (patch) | |
tree | e1a885aadfd80632f5bd70d4bd2d37e715e35a79 /lib/CodeGen | |
parent | fd035e6496665b1f1197868e21cb0a4594e8db6e (diff) | |
download | FreeBSD-src-df90325d4c0a65ee64d2dae3ed9b5b34f7418533.zip FreeBSD-src-df90325d4c0a65ee64d2dae3ed9b5b34f7418533.tar.gz |
Update clang to 97654.
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 144 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.h | 8 | ||||
-rw-r--r-- | lib/CodeGen/CGBuiltin.cpp | 75 | ||||
-rw-r--r-- | lib/CodeGen/CGCXX.cpp | 210 | ||||
-rw-r--r-- | lib/CodeGen/CGCall.cpp | 176 | ||||
-rw-r--r-- | lib/CodeGen/CGCall.h | 17 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 379 | ||||
-rw-r--r-- | lib/CodeGen/CGDebugInfo.cpp | 34 | ||||
-rw-r--r-- | lib/CodeGen/CGDebugInfo.h | 1 | ||||
-rw-r--r-- | lib/CodeGen/CGException.cpp | 68 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 16 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGObjCGNU.cpp | 25 | ||||
-rw-r--r-- | lib/CodeGen/CGObjCMac.cpp | 23 | ||||
-rw-r--r-- | lib/CodeGen/CGVTT.cpp | 21 | ||||
-rw-r--r-- | lib/CodeGen/CGVtable.cpp | 1549 | ||||
-rw-r--r-- | lib/CodeGen/CGVtable.h | 5 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.cpp | 119 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 66 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 64 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.h | 27 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenTypes.cpp | 12 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenTypes.h | 19 | ||||
-rw-r--r-- | lib/CodeGen/Mangle.cpp | 78 | ||||
-rw-r--r-- | lib/CodeGen/TargetInfo.cpp | 29 | ||||
-rw-r--r-- | lib/CodeGen/TargetInfo.h | 31 |
26 files changed, 2276 insertions, 922 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 46b6244..7076067 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -24,7 +24,7 @@ using namespace clang; using namespace CodeGen; llvm::Constant *CodeGenFunction:: -BuildDescriptorBlockDecl(bool BlockHasCopyDispose, CharUnits Size, +BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnits Size, const llvm::StructType* Ty, std::vector<HelperInfo> *NoteForHelper) { const llvm::Type *UnsignedLongTy @@ -43,6 +43,7 @@ BuildDescriptorBlockDecl(bool BlockHasCopyDispose, CharUnits Size, C = llvm::ConstantInt::get(UnsignedLongTy, Size.getQuantity()); Elts.push_back(C); + // optional copy/dispose helpers if (BlockHasCopyDispose) { // copy_func_helper_decl Elts.push_back(BuildCopyHelper(Ty, NoteForHelper)); @@ -51,6 +52,17 @@ BuildDescriptorBlockDecl(bool BlockHasCopyDispose, CharUnits Size, Elts.push_back(BuildDestroyHelper(Ty, NoteForHelper)); } + // Signature. non-optional ObjC-style method descriptor @encode sequence + std::string BlockTypeEncoding; + CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding); + + Elts.push_back(llvm::ConstantExpr::getBitCast( + CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty)); + + // Layout. + C = llvm::ConstantInt::get(UnsignedLongTy, 0); + Elts.push_back(C); + C = llvm::ConstantStruct::get(VMContext, Elts, false); C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, @@ -110,19 +122,6 @@ static bool CanBlockBeGlobal(const CodeGenFunction::BlockInfo &Info) { /// invoke function. static void AllocateAllBlockDeclRefs(const CodeGenFunction::BlockInfo &Info, CodeGenFunction *CGF) { - // Always allocate self, as it is often handy in the debugger, even if there - // is no codegen in the block that uses it. This is also useful to always do - // this as if we didn't, we'd have to figure out all code that uses a self - // pointer, including implicit uses. - if (const ObjCMethodDecl *OMD - = dyn_cast_or_null<ObjCMethodDecl>(CGF->CurFuncDecl)) { - ImplicitParamDecl *SelfDecl = OMD->getSelfDecl(); - BlockDeclRefExpr *BDRE = new (CGF->getContext()) - BlockDeclRefExpr(SelfDecl, - SelfDecl->getType(), SourceLocation(), false); - CGF->AllocateBlockDecl(BDRE); - } - // FIXME: Also always forward the this pointer in C++ as well. for (size_t i = 0; i < Info.DeclRefs.size(); ++i) @@ -148,30 +147,14 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { size_t BlockFields = 5; - bool hasIntrospection = CGM.getContext().getLangOptions().BlockIntrospection; - - if (hasIntrospection) { - BlockFields++; - } std::vector<llvm::Constant*> Elts(BlockFields); - if (hasIntrospection) { - std::string BlockTypeEncoding; - CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding); - - Elts[5] = llvm::ConstantExpr::getBitCast( - CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty); - } - llvm::Constant *C; llvm::Value *V; { // C = BuildBlockStructInitlist(); - unsigned int flags = BLOCK_HAS_DESCRIPTOR; - - if (hasIntrospection) - flags |= BLOCK_HAS_OBJC_TYPE; + unsigned int flags = BLOCK_HAS_OBJC_TYPE; // We run this first so that we set BlockHasCopyDispose from the entire // block literal. @@ -212,7 +195,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { if (subBlockDeclRefDecls.size() == 0) { // __descriptor - Elts[4] = BuildDescriptorBlockDecl(subBlockHasCopyDispose, subBlockSize, + Elts[4] = BuildDescriptorBlockDecl(BE, subBlockHasCopyDispose, subBlockSize, 0, 0); // Optimize to being a global block. @@ -234,8 +217,6 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { for (int i=0; i<4; ++i) Types[i] = Elts[i]->getType(); Types[4] = PtrToInt8Ty; - if (hasIntrospection) - Types[5] = PtrToInt8Ty; for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) { const Expr *E = subBlockDeclRefDecls[i]; @@ -258,8 +239,6 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { for (unsigned i=0; i<4; ++i) Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp")); - if (hasIntrospection) - Builder.CreateStore(Elts[5], Builder.CreateStructGEP(V, 5, "block.tmp")); for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) { @@ -348,7 +327,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { NoteForHelper.resize(helpersize); // __descriptor - llvm::Value *Descriptor = BuildDescriptorBlockDecl(subBlockHasCopyDispose, + llvm::Value *Descriptor = BuildDescriptorBlockDecl(BE, + subBlockHasCopyDispose, subBlockSize, Ty, &NoteForHelper); Descriptor = Builder.CreateBitCast(Descriptor, PtrToInt8Ty); @@ -384,6 +364,16 @@ const llvm::Type *BlockModule::getBlockDescriptorType() { // struct __block_descriptor { // unsigned long reserved; // unsigned long block_size; + // + // // later, the following will be added + // + // struct { + // void (*copyHelper)(); + // void (*copyHelper)(); + // } helpers; // !!! optional + // + // const char *signature; // the block signature + // const char *layout; // reserved // }; BlockDescriptorType = llvm::StructType::get(UnsignedLongTy->getContext(), UnsignedLongTy, @@ -412,20 +402,8 @@ const llvm::Type *BlockModule::getGenericBlockLiteralType() { // int __reserved; // void (*__invoke)(void *); // struct __block_descriptor *__descriptor; - // // GNU runtime only: - // const char *types; // }; - if (CGM.getContext().getLangOptions().BlockIntrospection) - GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(), - PtrToInt8Ty, - IntTy, - IntTy, - PtrToInt8Ty, - BlockDescPtrTy, - PtrToInt8Ty, - NULL); - else - GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(), + GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(), PtrToInt8Ty, IntTy, IntTy, @@ -439,40 +417,6 @@ const llvm::Type *BlockModule::getGenericBlockLiteralType() { return GenericBlockLiteralType; } -const llvm::Type *BlockModule::getGenericExtendedBlockLiteralType() { - if (GenericExtendedBlockLiteralType) - return GenericExtendedBlockLiteralType; - - const llvm::Type *BlockDescPtrTy = - llvm::PointerType::getUnqual(getBlockDescriptorType()); - - const llvm::IntegerType *IntTy = cast<llvm::IntegerType>( - getTypes().ConvertType(getContext().IntTy)); - - // struct __block_literal_generic { - // void *__isa; - // int __flags; - // int __reserved; - // void (*__invoke)(void *); - // struct __block_descriptor *__descriptor; - // void *__copy_func_helper_decl; - // void *__destroy_func_decl; - // }; - GenericExtendedBlockLiteralType = llvm::StructType::get(IntTy->getContext(), - PtrToInt8Ty, - IntTy, - IntTy, - PtrToInt8Ty, - BlockDescPtrTy, - PtrToInt8Ty, - PtrToInt8Ty, - NULL); - - getModule().addTypeName("struct.__block_literal_extended_generic", - GenericExtendedBlockLiteralType); - - return GenericExtendedBlockLiteralType; -} RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, ReturnValueSlot ReturnValue) { @@ -603,7 +547,7 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { const llvm::IntegerType *IntTy = cast<llvm::IntegerType>( getTypes().ConvertType(getContext().IntTy)); - llvm::Constant *DescriptorFields[2]; + llvm::Constant *DescriptorFields[4]; // Reserved DescriptorFields[0] = llvm::Constant::getNullValue(UnsignedLongTy); @@ -614,9 +558,21 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { CGM.GetTargetTypeStoreSize(getGenericBlockLiteralType()); DescriptorFields[1] = llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize.getQuantity()); + + // signature. non-optional ObjC-style method descriptor @encode sequence + std::string BlockTypeEncoding; + CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding); + DescriptorFields[2] = llvm::ConstantExpr::getBitCast( + CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty); + + // layout + DescriptorFields[3] = + llvm::ConstantInt::get(UnsignedLongTy,0); + + // build the structure from the 4 elements llvm::Constant *DescriptorStruct = - llvm::ConstantStruct::get(VMContext, &DescriptorFields[0], 2, false); + llvm::ConstantStruct::get(VMContext, &DescriptorFields[0], 4, false); llvm::GlobalVariable *Descriptor = new llvm::GlobalVariable(getModule(), DescriptorStruct->getType(), true, @@ -625,8 +581,6 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { int FieldCount = 5; // Generate the constants for the block literal. - if (CGM.getContext().getLangOptions().BlockIntrospection) - FieldCount = 6; std::vector<llvm::Constant*> LiteralFields(FieldCount); @@ -649,10 +603,8 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { LiteralFields[0] = getNSConcreteGlobalBlock(); // Flags - LiteralFields[1] = CGM.getContext().getLangOptions().BlockIntrospection ? - llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR | - BLOCK_HAS_OBJC_TYPE) : - llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR); + LiteralFields[1] = + llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_OBJC_TYPE); // Reserved LiteralFields[2] = llvm::Constant::getNullValue(IntTy); @@ -663,14 +615,6 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { // Descriptor LiteralFields[4] = Descriptor; - // Type encoding - if (CGM.getContext().getLangOptions().BlockIntrospection) { - std::string BlockTypeEncoding; - CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding); - - LiteralFields[5] = CGM.GetAddrOfConstantCString(BlockTypeEncoding); - } - llvm::Constant *BlockLiteralStruct = llvm::ConstantStruct::get(VMContext, LiteralFields, false); diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index a9f5ae0..39f26f8 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -51,12 +51,9 @@ class CodeGenModule; class BlockBase { public: enum { - BLOCK_NEEDS_FREE = (1 << 24), BLOCK_HAS_COPY_DISPOSE = (1 << 25), BLOCK_HAS_CXX_OBJ = (1 << 26), - BLOCK_IS_GC = (1 << 27), BLOCK_IS_GLOBAL = (1 << 28), - BLOCK_HAS_DESCRIPTOR = (1 << 29), BLOCK_HAS_OBJC_TYPE = (1 << 30) }; }; @@ -80,7 +77,6 @@ public: const llvm::Type *getBlockDescriptorType(); const llvm::Type *getGenericBlockLiteralType(); - const llvm::Type *getGenericExtendedBlockLiteralType(); llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, const char *); @@ -94,7 +90,7 @@ public: const llvm::Type *BlockDescriptorType; const llvm::Type *GenericBlockLiteralType; - const llvm::Type *GenericExtendedBlockLiteralType; + struct { int GlobalUniqueCount; } Block; @@ -111,7 +107,7 @@ public: : Context(C), TheModule(M), TheTargetData(TD), Types(T), CGM(CodeGen), VMContext(M.getContext()), NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockDescriptorType(0), - GenericBlockLiteralType(0), GenericExtendedBlockLiteralType(0), + GenericBlockLiteralType(0), BlockObjectAssign(0), BlockObjectDispose(0) { Block.GlobalUniqueCount = 0; PtrToInt8Ty = llvm::Type::getInt8PtrTy(M.getContext()); diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index beaf7b8..0f5e90f 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "TargetInfo.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "clang/Basic/TargetInfo.h" @@ -19,6 +20,7 @@ #include "clang/AST/Decl.h" #include "clang/Basic/TargetBuiltins.h" #include "llvm/Intrinsics.h" +#include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; using namespace llvm; @@ -57,6 +59,10 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF, return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Operand)); } +static llvm::ConstantInt *getInt32(llvm::LLVMContext &Context, int32_t Value) { + return llvm::ConstantInt::get(llvm::Type::getInt32Ty(Context), Value); +} + RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, unsigned BuiltinID, const CallExpr *E) { // See if we can constant fold this builtin. If so, don't emit it at all. @@ -341,6 +347,20 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1)); return RValue::get(Address); } + case Builtin::BI__builtin_dwarf_cfa: { + // The offset in bytes from the first argument to the CFA. + // + // Why on earth is this in the frontend? Is there any reason at + // all that the backend can't reasonably determine this while + // lowering llvm.eh.dwarf.cfa()? + // + // TODO: If there's a satisfactory reason, add a target hook for + // this instead of hard-coding 0, which is correct for most targets. + int32_t Offset = 0; + + Value *F = CGM.getIntrinsic(Intrinsic::eh_dwarf_cfa, 0, 0); + return RValue::get(Builder.CreateCall(F, getInt32(VMContext, Offset))); + } case Builtin::BI__builtin_return_address: { Value *Depth = EmitScalarExpr(E->getArg(0)); Depth = Builder.CreateIntCast(Depth, @@ -358,13 +378,64 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall(F, Depth)); } case Builtin::BI__builtin_extract_return_addr: { - // FIXME: There should be a target hook for this - return RValue::get(EmitScalarExpr(E->getArg(0))); + Value *Address = EmitScalarExpr(E->getArg(0)); + Value *Result = getTargetHooks().decodeReturnAddress(*this, Address); + return RValue::get(Result); + } + case Builtin::BI__builtin_frob_return_addr: { + Value *Address = EmitScalarExpr(E->getArg(0)); + Value *Result = getTargetHooks().encodeReturnAddress(*this, Address); + return RValue::get(Result); + } + case Builtin::BI__builtin_eh_return: { + Value *Int = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + + const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(Int->getType()); + assert((IntTy->getBitWidth() == 32 || IntTy->getBitWidth() == 64) && + "LLVM's __builtin_eh_return only supports 32- and 64-bit variants"); + Value *F = CGM.getIntrinsic(IntTy->getBitWidth() == 32 + ? Intrinsic::eh_return_i32 + : Intrinsic::eh_return_i64, + 0, 0); + Builder.CreateCall2(F, Int, Ptr); + Value *V = Builder.CreateUnreachable(); + Builder.ClearInsertionPoint(); + return RValue::get(V); } case Builtin::BI__builtin_unwind_init: { Value *F = CGM.getIntrinsic(Intrinsic::eh_unwind_init, 0, 0); return RValue::get(Builder.CreateCall(F)); } + case Builtin::BI__builtin_extend_pointer: { + // Extends a pointer to the size of an _Unwind_Word, which is + // uint64_t on all platforms. Generally this gets poked into a + // register and eventually used as an address, so if the + // addressing registers are wider than pointers and the platform + // doesn't implicitly ignore high-order bits when doing + // addressing, we need to make sure we zext / sext based on + // the platform's expectations. + // + // See: http://gcc.gnu.org/ml/gcc-bugs/2002-02/msg00237.html + + LLVMContext &C = CGM.getLLVMContext(); + + // Cast the pointer to intptr_t. + Value *Ptr = EmitScalarExpr(E->getArg(0)); + const llvm::IntegerType *IntPtrTy = CGM.getTargetData().getIntPtrType(C); + Value *Result = Builder.CreatePtrToInt(Ptr, IntPtrTy, "extend.cast"); + + // If that's 64 bits, we're done. + if (IntPtrTy->getBitWidth() == 64) + return RValue::get(Result); + + // Otherwise, ask the codegen data what to do. + const llvm::IntegerType *Int64Ty = llvm::IntegerType::get(C, 64); + if (getTargetHooks().extendPointerWithSExt()) + return RValue::get(Builder.CreateSExt(Result, Int64Ty, "extend.sext")); + else + return RValue::get(Builder.CreateZExt(Result, Int64Ty, "extend.zext")); + } #if 0 // FIXME: Finish/enable when LLVM backend support stabilizes case Builtin::BI__builtin_setjmp: { diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 28c4c6b..4889fc0 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -22,33 +22,182 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/StmtCXX.h" +#include "clang/CodeGen/CodeGenOptions.h" #include "llvm/ADT/StringExtras.h" using namespace clang; using namespace CodeGen; +/// Determines whether the given function has a trivial body that does +/// not require any specific codegen. +static bool HasTrivialBody(const FunctionDecl *FD) { + Stmt *S = FD->getBody(); + if (!S) + return true; + if (isa<CompoundStmt>(S) && cast<CompoundStmt>(S)->body_empty()) + return true; + return false; +} + +/// Try to emit a base destructor as an alias to its primary +/// base-class destructor. +bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) { + if (!getCodeGenOpts().CXXCtorDtorAliases) + return true; + + // If the destructor doesn't have a trivial body, we have to emit it + // separately. + if (!HasTrivialBody(D)) + return true; + + const CXXRecordDecl *Class = D->getParent(); + + // If we need to manipulate a VTT parameter, give up. + if (Class->getNumVBases()) { + // Extra Credit: passing extra parameters is perfectly safe + // in many calling conventions, so only bail out if the ctor's + // calling convention is nonstandard. + return true; + } + + // If any fields have a non-trivial destructor, we have to emit it + // separately. + for (CXXRecordDecl::field_iterator I = Class->field_begin(), + E = Class->field_end(); I != E; ++I) + if (const RecordType *RT = (*I)->getType()->getAs<RecordType>()) + if (!cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor()) + return true; + + // Try to find a unique base class with a non-trivial destructor. + const CXXRecordDecl *UniqueBase = 0; + for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(), + E = Class->bases_end(); I != E; ++I) { + + // We're in the base destructor, so skip virtual bases. + if (I->isVirtual()) continue; + + // Skip base classes with trivial destructors. + const CXXRecordDecl *Base + = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + if (Base->hasTrivialDestructor()) continue; + + // If we've already found a base class with a non-trivial + // destructor, give up. + if (UniqueBase) return true; + UniqueBase = Base; + } + + // If we didn't find any bases with a non-trivial destructor, then + // the base destructor is actually effectively trivial, which can + // happen if it was needlessly user-defined or if there are virtual + // bases with non-trivial destructors. + if (!UniqueBase) + return true; + + /// If we don't have a definition for the destructor yet, don't + /// emit. We can't emit aliases to declarations; that's just not + /// how aliases work. + const CXXDestructorDecl *BaseD = UniqueBase->getDestructor(getContext()); + if (!BaseD->isImplicit() && !BaseD->getBody()) + return true; + + // If the base is at a non-zero offset, give up. + const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(Class); + if (ClassLayout.getBaseClassOffset(UniqueBase) != 0) + return true; + + return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base), + GlobalDecl(BaseD, Dtor_Base)); +} +/// Try to emit a definition as a global alias for another definition. +bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, + GlobalDecl TargetDecl) { + if (!getCodeGenOpts().CXXCtorDtorAliases) + return true; + + // The alias will use the linkage of the referrent. If we can't + // support aliases with that linkage, fail. + llvm::GlobalValue::LinkageTypes Linkage + = getFunctionLinkage(cast<FunctionDecl>(AliasDecl.getDecl())); + + switch (Linkage) { + // We can definitely emit aliases to definitions with external linkage. + case llvm::GlobalValue::ExternalLinkage: + case llvm::GlobalValue::ExternalWeakLinkage: + break; + + // Same with local linkage. + case llvm::GlobalValue::InternalLinkage: + case llvm::GlobalValue::PrivateLinkage: + case llvm::GlobalValue::LinkerPrivateLinkage: + break; + + // We should try to support linkonce linkages. + case llvm::GlobalValue::LinkOnceAnyLinkage: + case llvm::GlobalValue::LinkOnceODRLinkage: + return true; + + // Other linkages will probably never be supported. + default: + return true; + } + + // Derive the type for the alias. + const llvm::PointerType *AliasType + = getTypes().GetFunctionType(AliasDecl)->getPointerTo(); + + // Find the referrent. Some aliases might require a bitcast, in + // which case the caller is responsible for ensuring the soundness + // of these semantics. + llvm::GlobalValue *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl)); + llvm::Constant *Aliasee = Ref; + if (Ref->getType() != AliasType) + Aliasee = llvm::ConstantExpr::getBitCast(Ref, AliasType); + + // Create the alias with no name. + llvm::GlobalAlias *Alias = + new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule()); + + // Switch any previous uses to the alias. + const char *MangledName = getMangledName(AliasDecl); + llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName]; + if (Entry) { + assert(Entry->isDeclaration() && "definition already exists for alias"); + assert(Entry->getType() == AliasType && + "declaration exists with different type"); + Entry->replaceAllUsesWith(Alias); + Entry->eraseFromParent(); + } + Entry = Alias; -llvm::Value *CodeGenFunction::LoadCXXThis() { - assert(isa<CXXMethodDecl>(CurFuncDecl) && - "Must be in a C++ member function decl to load 'this'"); - assert(cast<CXXMethodDecl>(CurFuncDecl)->isInstance() && - "Must be in a C++ member function decl to load 'this'"); + // Finally, set up the alias with its proper name and attributes. + Alias->setName(MangledName); + SetCommonAttributes(AliasDecl.getDecl(), Alias); - // FIXME: What if we're inside a block? - // ans: See how CodeGenFunction::LoadObjCSelf() uses - // CodeGenFunction::BlockForwardSelf() for how to do this. - return Builder.CreateLoad(LocalDeclMap[CXXThisDecl], "this"); + return false; } void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) { + // The constructor used for constructing this as a complete class; + // constucts the virtual bases, then calls the base constructor. EmitGlobal(GlobalDecl(D, Ctor_Complete)); + + // The constructor used for constructing this as a base class; + // ignores virtual bases. EmitGlobal(GlobalDecl(D, Ctor_Base)); } void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type) { + // The complete constructor is equivalent to the base constructor + // for classes with no virtual bases. Try to emit it as an alias. + if (Type == Ctor_Complete && + !D->getParent()->getNumVBases() && + !TryEmitDefinitionAsAlias(GlobalDecl(D, Ctor_Complete), + GlobalDecl(D, Ctor_Base))) + return; - llvm::Function *Fn = GetAddrOfCXXConstructor(D, Type); + llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXConstructor(D, Type)); CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn); @@ -56,15 +205,17 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D, SetLLVMFunctionAttributesForDefinition(D, Fn); } -llvm::Function * +llvm::GlobalValue * CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type) { + const char *Name = getMangledCXXCtorName(D, Type); + if (llvm::GlobalValue *V = GlobalDeclMap[Name]) + return V; + const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>(); const llvm::FunctionType *FTy = getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type), FPT->isVariadic()); - - const char *Name = getMangledCXXCtorName(D, Type); return cast<llvm::Function>( GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type))); } @@ -79,15 +230,39 @@ const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D, } void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { + // The destructor in a virtual table is always a 'deleting' + // destructor, which calls the complete destructor and then uses the + // appropriate operator delete. if (D->isVirtual()) EmitGlobal(GlobalDecl(D, Dtor_Deleting)); + + // The destructor used for destructing this as a most-derived class; + // call the base destructor and then destructs any virtual bases. EmitGlobal(GlobalDecl(D, Dtor_Complete)); + + // The destructor used for destructing this as a base class; ignores + // virtual bases. EmitGlobal(GlobalDecl(D, Dtor_Base)); } void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type) { - llvm::Function *Fn = GetAddrOfCXXDestructor(D, Type); + // The complete destructor is equivalent to the base destructor for + // classes with no virtual bases, so try to emit it as an alias. + if (Type == Dtor_Complete && + !D->getParent()->getNumVBases() && + !TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Complete), + GlobalDecl(D, Dtor_Base))) + return; + + // The base destructor is equivalent to the base destructor of its + // base class if there is exactly one non-virtual base class with a + // non-trivial destructor, there are no fields with a non-trivial + // destructor, and the body of the destructor is trivial. + if (Type == Dtor_Base && !TryEmitBaseDestructorAsAlias(D)) + return; + + llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXDestructor(D, Type)); CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn); @@ -95,13 +270,16 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D, SetLLVMFunctionAttributesForDefinition(D, Fn); } -llvm::Function * +llvm::GlobalValue * CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type) { + const char *Name = getMangledCXXDtorName(D, Type); + if (llvm::GlobalValue *V = GlobalDeclMap[Name]) + return V; + const llvm::FunctionType *FTy = getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type), false); - const char *Name = getMangledCXXDtorName(D, Type); return cast<llvm::Function>( GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type))); } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index b064c12..072b1f6 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -41,21 +41,54 @@ static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) { } } -const -CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionNoProtoType *FTNP) { - return getFunctionInfo(FTNP->getResultType(), - llvm::SmallVector<QualType, 16>(), - FTNP->getCallConv(), FTNP->getNoReturnAttr()); +/// Derives the 'this' type for codegen purposes, i.e. ignoring method +/// qualification. +/// FIXME: address space qualification? +static CanQualType GetThisType(ASTContext &Context, const CXXRecordDecl *RD) { + QualType RecTy = Context.getTagDeclType(RD)->getCanonicalTypeInternal(); + return Context.getPointerType(CanQualType::CreateUnsafe(RecTy)); } -const -CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionProtoType *FTP) { - llvm::SmallVector<QualType, 16> ArgTys; +/// Returns the canonical formal type of the given C++ method. +static CanQual<FunctionProtoType> GetFormalType(const CXXMethodDecl *MD) { + return MD->getType()->getCanonicalTypeUnqualified() + .getAs<FunctionProtoType>(); +} + +/// Returns the "extra-canonicalized" return type, which discards +/// qualifiers on the return type. Codegen doesn't care about them, +/// and it makes ABI code a little easier to be able to assume that +/// all parameter and return types are top-level unqualified. +static CanQualType GetReturnType(QualType RetTy) { + return RetTy->getCanonicalTypeUnqualified().getUnqualifiedType(); +} + +const CGFunctionInfo & +CodeGenTypes::getFunctionInfo(CanQual<FunctionNoProtoType> FTNP) { + return getFunctionInfo(FTNP->getResultType().getUnqualifiedType(), + llvm::SmallVector<CanQualType, 16>(), + FTNP->getCallConv(), + FTNP->getNoReturnAttr()); +} + +/// \param Args - contains any initial parameters besides those +/// in the formal type +static const CGFunctionInfo &getFunctionInfo(CodeGenTypes &CGT, + llvm::SmallVectorImpl<CanQualType> &ArgTys, + CanQual<FunctionProtoType> FTP) { // FIXME: Kill copy. for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, - FTP->getCallConv(), FTP->getNoReturnAttr()); + CanQualType ResTy = FTP->getResultType().getUnqualifiedType(); + return CGT.getFunctionInfo(ResTy, ArgTys, + FTP->getCallConv(), + FTP->getNoReturnAttr()); +} + +const CGFunctionInfo & +CodeGenTypes::getFunctionInfo(CanQual<FunctionProtoType> FTP) { + llvm::SmallVector<CanQualType, 16> ArgTys; + return ::getFunctionInfo(*this, ArgTys, FTP); } static CallingConv getCallingConventionForDecl(const Decl *D) { @@ -71,67 +104,51 @@ static CallingConv getCallingConventionForDecl(const Decl *D) { const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, const FunctionProtoType *FTP) { - llvm::SmallVector<QualType, 16> ArgTys; - + llvm::SmallVector<CanQualType, 16> ArgTys; + // Add the 'this' pointer. - ArgTys.push_back(Context.getPointerType(Context.getTagDeclType(RD))); - - for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) - ArgTys.push_back(FTP->getArgType(i)); - - // FIXME: Set calling convention correctly, it needs to be associated with the - // type somehow. - return getFunctionInfo(FTP->getResultType(), ArgTys, - FTP->getCallConv(), FTP->getNoReturnAttr()); + ArgTys.push_back(GetThisType(Context, RD)); + + return ::getFunctionInfo(*this, ArgTys, + FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { - llvm::SmallVector<QualType, 16> ArgTys; + llvm::SmallVector<CanQualType, 16> ArgTys; + // Add the 'this' pointer unless this is a static method. if (MD->isInstance()) - ArgTys.push_back(MD->getThisType(Context)); + ArgTys.push_back(GetThisType(Context, MD->getParent())); - const FunctionProtoType *FTP = MD->getType()->getAs<FunctionProtoType>(); - for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) - ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(), - FTP->getNoReturnAttr()); + return ::getFunctionInfo(*this, ArgTys, GetFormalType(MD)); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D, CXXCtorType Type) { - llvm::SmallVector<QualType, 16> ArgTys; + llvm::SmallVector<CanQualType, 16> ArgTys; // Add the 'this' pointer. - ArgTys.push_back(D->getThisType(Context)); + ArgTys.push_back(GetThisType(Context, D->getParent())); // Check if we need to add a VTT parameter (which has type void **). if (Type == Ctor_Base && D->getParent()->getNumVBases() != 0) ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); - - const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>(); - for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) - ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(), - FTP->getNoReturnAttr()); + + return ::getFunctionInfo(*this, ArgTys, GetFormalType(D)); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D, CXXDtorType Type) { - llvm::SmallVector<QualType, 16> ArgTys; + llvm::SmallVector<CanQualType, 16> ArgTys; // Add the 'this' pointer. - ArgTys.push_back(D->getThisType(Context)); + ArgTys.push_back(GetThisType(Context, D->getParent())); // Check if we need to add a VTT parameter (which has type void **). if (Type == Dtor_Base && D->getParent()->getNumVBases() != 0) ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); - - const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>(); - for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) - ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(), - FTP->getNoReturnAttr()); + + return ::getFunctionInfo(*this, ArgTys, GetFormalType(D)); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) { @@ -139,30 +156,25 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) { if (MD->isInstance()) return getFunctionInfo(MD); - const FunctionType *FTy = FD->getType()->getAs<FunctionType>(); - if (const FunctionNoProtoType *FNTP = dyn_cast<FunctionNoProtoType>(FTy)) - return getFunctionInfo(FNTP->getResultType(), - llvm::SmallVector<QualType, 16>(), - FNTP->getCallConv(), FNTP->getNoReturnAttr()); - - const FunctionProtoType *FPT = cast<FunctionProtoType>(FTy); - llvm::SmallVector<QualType, 16> ArgTys; - // FIXME: Kill copy. - for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i) - ArgTys.push_back(FPT->getArgType(i)); - return getFunctionInfo(FPT->getResultType(), ArgTys, - FPT->getCallConv(), FPT->getNoReturnAttr()); + CanQualType FTy = FD->getType()->getCanonicalTypeUnqualified(); + assert(isa<FunctionType>(FTy)); + if (isa<FunctionNoProtoType>(FTy)) + return getFunctionInfo(FTy.getAs<FunctionNoProtoType>()); + assert(isa<FunctionProtoType>(FTy)); + return getFunctionInfo(FTy.getAs<FunctionProtoType>()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { - llvm::SmallVector<QualType, 16> ArgTys; - ArgTys.push_back(MD->getSelfDecl()->getType()); - ArgTys.push_back(Context.getObjCSelType()); + llvm::SmallVector<CanQualType, 16> ArgTys; + ArgTys.push_back(Context.getCanonicalParamType(MD->getSelfDecl()->getType())); + ArgTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType())); // FIXME: Kill copy? for (ObjCMethodDecl::param_iterator i = MD->param_begin(), - e = MD->param_end(); i != e; ++i) - ArgTys.push_back((*i)->getType()); - return getFunctionInfo(MD->getResultType(), ArgTys, + e = MD->param_end(); i != e; ++i) { + ArgTys.push_back(Context.getCanonicalParamType((*i)->getType())); + } + return getFunctionInfo(GetReturnType(MD->getResultType()), + ArgTys, getCallingConventionForDecl(MD), /*NoReturn*/ false); } @@ -185,11 +197,11 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, CallingConv CC, bool NoReturn) { // FIXME: Kill copy. - llvm::SmallVector<QualType, 16> ArgTys; + llvm::SmallVector<CanQualType, 16> ArgTys; for (CallArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) - ArgTys.push_back(i->second); - return getFunctionInfo(ResTy, ArgTys, CC, NoReturn); + ArgTys.push_back(Context.getCanonicalParamType(i->second)); + return getFunctionInfo(GetReturnType(ResTy), ArgTys, CC, NoReturn); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, @@ -197,17 +209,23 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, CallingConv CC, bool NoReturn) { // FIXME: Kill copy. - llvm::SmallVector<QualType, 16> ArgTys; + llvm::SmallVector<CanQualType, 16> ArgTys; for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) - ArgTys.push_back(i->second); - return getFunctionInfo(ResTy, ArgTys, CC, NoReturn); + ArgTys.push_back(Context.getCanonicalParamType(i->second)); + return getFunctionInfo(GetReturnType(ResTy), ArgTys, CC, NoReturn); } -const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, - const llvm::SmallVector<QualType, 16> &ArgTys, +const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, + const llvm::SmallVectorImpl<CanQualType> &ArgTys, CallingConv CallConv, bool NoReturn) { +#ifndef NDEBUG + for (llvm::SmallVectorImpl<CanQualType>::const_iterator + I = ArgTys.begin(), E = ArgTys.end(); I != E; ++I) + assert(I->isCanonicalAsParam()); +#endif + unsigned CC = ClangCallConvToLLVMCallConv(CallConv); // Lookup or create unique function info. @@ -232,8 +250,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, bool _NoReturn, - QualType ResTy, - const llvm::SmallVector<QualType, 16> &ArgTys) + CanQualType ResTy, + const llvm::SmallVectorImpl<CanQualType> &ArgTys) : CallingConvention(_CallingConvention), EffectiveCallingConvention(_CallingConvention), NoReturn(_NoReturn) @@ -416,6 +434,18 @@ bool CodeGenModule::ReturnTypeUsesSret(const CGFunctionInfo &FI) { return FI.getReturnInfo().isIndirect(); } +const llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) { + const CGFunctionInfo &FI = getFunctionInfo(GD); + + // For definition purposes, don't consider a K&R function variadic. + bool Variadic = false; + if (const FunctionProtoType *FPT = + cast<FunctionDecl>(GD.getDecl())->getType()->getAs<FunctionProtoType>()) + Variadic = FPT->isVariadic(); + + return GetFunctionType(FI, Variadic); +} + const llvm::FunctionType * CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) { std::vector<const llvm::Type*> ArgTys; diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h index 9601e9a..3d81165 100644 --- a/lib/CodeGen/CGCall.h +++ b/lib/CodeGen/CGCall.h @@ -18,6 +18,7 @@ #include "llvm/ADT/FoldingSet.h" #include "llvm/Value.h" #include "clang/AST/Type.h" +#include "clang/AST/CanonicalType.h" #include "CGValue.h" @@ -57,7 +58,7 @@ namespace CodeGen { /// function definition. class CGFunctionInfo : public llvm::FoldingSetNode { struct ArgInfo { - QualType type; + CanQualType type; ABIArgInfo info; }; @@ -81,8 +82,8 @@ namespace CodeGen { CGFunctionInfo(unsigned CallingConvention, bool NoReturn, - QualType ResTy, - const llvm::SmallVector<QualType, 16> &ArgTys); + CanQualType ResTy, + const llvm::SmallVectorImpl<CanQualType> &ArgTys); ~CGFunctionInfo() { delete[] Args; } const_arg_iterator arg_begin() const { return Args + 1; } @@ -107,7 +108,7 @@ namespace CodeGen { EffectiveCallingConvention = Value; } - QualType getReturnType() const { return Args[0].type; } + CanQualType getReturnType() const { return Args[0].type; } ABIArgInfo &getReturnInfo() { return Args[0].info; } const ABIArgInfo &getReturnInfo() const { return Args[0].info; } @@ -123,14 +124,16 @@ namespace CodeGen { static void Profile(llvm::FoldingSetNodeID &ID, unsigned CallingConvention, bool NoReturn, - QualType ResTy, + CanQualType ResTy, Iterator begin, Iterator end) { ID.AddInteger(CallingConvention); ID.AddBoolean(NoReturn); ResTy.Profile(ID); - for (; begin != end; ++begin) - begin->Profile(ID); + for (; begin != end; ++begin) { + CanQualType T = *begin; // force iterator to be over canonical types + T.Profile(ID); + } } }; diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index fa5a47f..99c6dfd 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -14,6 +14,7 @@ #include "CodeGenFunction.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/StmtCXX.h" using namespace clang; using namespace CodeGen; @@ -477,12 +478,21 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { const CXXRecordDecl *RD = cast<CXXMethodDecl>(CGF.CurFuncDecl)->getParent(); const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent(); - + llvm::Value *VTT; - uint64_t SubVTTIndex = - CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base); - assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!"); + uint64_t SubVTTIndex; + + // If the record matches the base, this is the complete ctor/dtor + // variant calling the base variant in a class with virtual bases. + if (RD == Base) { + assert(!CGVtableInfo::needsVTTParameter(CGF.CurGD) && + "doing no-op VTT offset in base dtor/ctor?"); + SubVTTIndex = 0; + } else { + SubVTTIndex = CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base); + assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!"); + } if (CGVtableInfo::needsVTTParameter(CGF.CurGD)) { // A VTT parameter was passed to the constructor, use it. @@ -590,19 +600,6 @@ void CodeGenFunction::EmitClassCopyAssignment( Callee, ReturnValueSlot(), CallArgs, MD); } -/// SynthesizeDefaultConstructor - synthesize a default constructor -void -CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor, - CXXCtorType Type, - llvm::Function *Fn, - const FunctionArgList &Args) { - assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor"); - StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, - SourceLocation()); - EmitCtorPrologue(Ctor, Type); - FinishFunction(); -} - /// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a /// copy constructor, in accordance with section 12.8 (p7 and p8) of C++03 /// The implicitly-defined copy constructor for class X performs a memberwise @@ -619,16 +616,12 @@ CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor, /// implicitly-defined copy constructor void -CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, - CXXCtorType Type, - llvm::Function *Fn, - const FunctionArgList &Args) { +CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) { + const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl()); const CXXRecordDecl *ClassDecl = Ctor->getParent(); assert(!ClassDecl->hasUserDeclaredCopyConstructor() && "SynthesizeCXXCopyConstructor - copy constructor has definition already"); assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor"); - StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, - SourceLocation()); FunctionArgList::const_iterator i = Args.begin(); const VarDecl *ThisArg = i->first; @@ -698,7 +691,6 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, } InitializeVtablePtrs(ClassDecl); - FinishFunction(); } /// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator. @@ -721,14 +713,11 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, /// /// if the subobject is of scalar type, the built-in assignment operator is /// used. -void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, - llvm::Function *Fn, - const FunctionArgList &Args) { - +void CodeGenFunction::SynthesizeCXXCopyAssignment(const FunctionArgList &Args) { + const CXXMethodDecl *CD = cast<CXXMethodDecl>(CurGD.getDecl()); const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext()); assert(!ClassDecl->hasUserDeclaredCopyAssignment() && "SynthesizeCXXCopyAssignment - copy assignment has user declaration"); - StartFunction(CD, CD->getResultType(), Fn, Args, SourceLocation()); FunctionArgList::const_iterator i = Args.begin(); const VarDecl *ThisArg = i->first; @@ -796,8 +785,6 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, // return *this; Builder.CreateStore(LoadOfThis, ReturnValue); - - FinishFunction(); } static void EmitBaseInitializer(CodeGenFunction &CGF, @@ -904,6 +891,101 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, } } +/// Checks whether the given constructor is a valid subject for the +/// complete-to-base constructor delegation optimization, i.e. +/// emitting the complete constructor as a simple call to the base +/// constructor. +static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor) { + + // Currently we disable the optimization for classes with virtual + // bases because (1) the addresses of parameter variables need to be + // consistent across all initializers but (2) the delegate function + // call necessarily creates a second copy of the parameter variable. + // + // The limiting example (purely theoretical AFAIK): + // struct A { A(int &c) { c++; } }; + // struct B : virtual A { + // B(int count) : A(count) { printf("%d\n", count); } + // }; + // ...although even this example could in principle be emitted as a + // delegation since the address of the parameter doesn't escape. + if (Ctor->getParent()->getNumVBases()) { + // TODO: white-list trivial vbase initializers. This case wouldn't + // be subject to the restrictions below. + + // TODO: white-list cases where: + // - there are no non-reference parameters to the constructor + // - the initializers don't access any non-reference parameters + // - the initializers don't take the address of non-reference + // parameters + // - etc. + // If we ever add any of the above cases, remember that: + // - function-try-blocks will always blacklist this optimization + // - we need to perform the constructor prologue and cleanup in + // EmitConstructorBody. + + return false; + } + + // We also disable the optimization for variadic functions because + // it's impossible to "re-pass" varargs. + if (Ctor->getType()->getAs<FunctionProtoType>()->isVariadic()) + return false; + + return true; +} + +/// EmitConstructorBody - Emits the body of the current constructor. +void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { + const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl()); + CXXCtorType CtorType = CurGD.getCtorType(); + + // Before we go any further, try the complete->base constructor + // delegation optimization. + if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor)) { + EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args); + return; + } + + Stmt *Body = Ctor->getBody(); + + // Enter the function-try-block before the constructor prologue if + // applicable. + CXXTryStmtInfo TryInfo; + bool IsTryBody = (Body && isa<CXXTryStmt>(Body)); + + if (IsTryBody) + TryInfo = EnterCXXTryStmt(*cast<CXXTryStmt>(Body)); + + unsigned CleanupStackSize = CleanupEntries.size(); + + // Emit the constructor prologue, i.e. the base and member + // initializers. + EmitCtorPrologue(Ctor, CtorType); + + // Emit the body of the statement. + if (IsTryBody) + EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock()); + else if (Body) + EmitStmt(Body); + else { + assert(Ctor->isImplicit() && "bodyless ctor not implicit"); + if (!Ctor->isDefaultConstructor()) { + assert(Ctor->isCopyConstructor()); + SynthesizeCXXCopyConstructor(Args); + } + } + + // Emit any cleanup blocks associated with the member or base + // initializers, which includes (along the exceptional path) the + // destructors for those members and bases that were fully + // constructed. + EmitCleanupBlocks(CleanupStackSize); + + if (IsTryBody) + ExitCXXTryStmt(*cast<CXXTryStmt>(Body), TryInfo); +} + /// EmitCtorPrologue - This routine generates necessary code to initialize /// base classes and non-static data members belonging to this constructor. void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, @@ -938,10 +1020,87 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, } } +/// EmitDestructorBody - Emits the body of the current destructor. +void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { + const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl()); + CXXDtorType DtorType = CurGD.getDtorType(); + + Stmt *Body = Dtor->getBody(); + + // If the body is a function-try-block, enter the try before + // anything else --- unless we're in a deleting destructor, in which + // case we're just going to call the complete destructor and then + // call operator delete() on the way out. + CXXTryStmtInfo TryInfo; + bool isTryBody = (DtorType != Dtor_Deleting && + Body && isa<CXXTryStmt>(Body)); + if (isTryBody) + TryInfo = EnterCXXTryStmt(*cast<CXXTryStmt>(Body)); + + llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); + PushCleanupBlock(DtorEpilogue); + + bool SkipBody = false; // should get jump-threaded + + // If this is the deleting variant, just invoke the complete + // variant, then call the appropriate operator delete() on the way + // out. + if (DtorType == Dtor_Deleting) { + EmitCXXDestructorCall(Dtor, Dtor_Complete, LoadCXXThis()); + SkipBody = true; + + // If this is the complete variant, just invoke the base variant; + // the epilogue will destruct the virtual bases. But we can't do + // this optimization if the body is a function-try-block, because + // we'd introduce *two* handler blocks. + } else if (!isTryBody && DtorType == Dtor_Complete) { + EmitCXXDestructorCall(Dtor, Dtor_Base, LoadCXXThis()); + SkipBody = true; + + // Otherwise, we're in the base variant, so we need to ensure the + // vtable ptrs are right before emitting the body. + } else { + InitializeVtablePtrs(Dtor->getParent()); + } + + // Emit the body of the statement. + if (SkipBody) + (void) 0; + else if (isTryBody) + EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock()); + else if (Body) + EmitStmt(Body); + else { + assert(Dtor->isImplicit() && "bodyless dtor not implicit"); + // nothing to do besides what's in the epilogue + } + + // Jump to the cleanup block. + CleanupBlockInfo Info = PopCleanupBlock(); + assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!"); + EmitBlock(DtorEpilogue); + + // Emit the destructor epilogue now. If this is a complete + // destructor with a function-try-block, perform the base epilogue + // as well. + if (isTryBody && DtorType == Dtor_Complete) + EmitDtorEpilogue(Dtor, Dtor_Base); + EmitDtorEpilogue(Dtor, DtorType); + + // Link up the cleanup information. + if (Info.SwitchBlock) + EmitBlock(Info.SwitchBlock); + if (Info.EndBlock) + EmitBlock(Info.EndBlock); + + // Exit the try if applicable. + if (isTryBody) + ExitCXXTryStmt(*cast<CXXTryStmt>(Body), TryInfo); +} + /// EmitDtorEpilogue - Emit all code that comes at the end of class's /// destructor. This is to call destructors on members and base classes /// in reverse order of their construction. -/// FIXME: This needs to take a CXXDtorType. void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, CXXDtorType DtorType) { assert(!DD->isTrivial() && @@ -949,6 +1108,44 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, const CXXRecordDecl *ClassDecl = DD->getParent(); + // In a deleting destructor, we've already called the complete + // destructor as a subroutine, so we just have to delete the + // appropriate value. + if (DtorType == Dtor_Deleting) { + assert(DD->getOperatorDelete() && + "operator delete missing - EmitDtorEpilogue"); + EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(), + getContext().getTagDeclType(ClassDecl)); + return; + } + + // For complete destructors, we've already called the base + // destructor (in GenerateBody), so we just need to destruct all the + // virtual bases. + if (DtorType == Dtor_Complete) { + // Handle virtual bases. + for (CXXRecordDecl::reverse_base_class_const_iterator I = + ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); + I != E; ++I) { + const CXXBaseSpecifier &Base = *I; + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); + + // Ignore trivial destructors. + if (BaseClassDecl->hasTrivialDestructor()) + continue; + const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); + llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(), + true, + ClassDecl, + BaseClassDecl); + EmitCXXDestructorCall(D, Dtor_Base, V); + } + return; + } + + assert(DtorType == Dtor_Base); + // Collect the fields. llvm::SmallVector<const FieldDecl *, 16> FieldDecls; for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), @@ -1021,51 +1218,6 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, /*NullCheckValue=*/false); EmitCXXDestructorCall(D, Dtor_Base, V); } - - // If we're emitting a base destructor, we don't want to emit calls to the - // virtual bases. - if (DtorType == Dtor_Base) - return; - - // Handle virtual bases. - for (CXXRecordDecl::reverse_base_class_const_iterator I = - ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) { - const CXXBaseSpecifier &Base = *I; - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - - // Ignore trivial destructors. - if (BaseClassDecl->hasTrivialDestructor()) - continue; - const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); - llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(), - true, - ClassDecl, - BaseClassDecl); - EmitCXXDestructorCall(D, Dtor_Base, V); - } - - // If we have a deleting destructor, emit a call to the delete operator. - if (DtorType == Dtor_Deleting) { - assert(DD->getOperatorDelete() && - "operator delete missing - EmitDtorEpilogue"); - EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(), - getContext().getTagDeclType(ClassDecl)); - } -} - -void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, - CXXDtorType DtorType, - llvm::Function *Fn, - const FunctionArgList &Args) { - assert(!Dtor->getParent()->hasUserDeclaredDestructor() && - "SynthesizeDefaultDestructor - destructor has user declaration"); - - StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args, - SourceLocation()); - InitializeVtablePtrs(Dtor->getParent()); - EmitDtorEpilogue(Dtor, DtorType); - FinishFunction(); } /// EmitCXXAggrConstructorCall - This routine essentially creates a (nested) @@ -1303,6 +1455,71 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd); } +void +CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, + CXXCtorType CtorType, + const FunctionArgList &Args) { + CallArgList DelegateArgs; + + FunctionArgList::const_iterator I = Args.begin(), E = Args.end(); + assert(I != E && "no parameters to constructor"); + + // this + DelegateArgs.push_back(std::make_pair(RValue::get(LoadCXXThis()), + I->second)); + ++I; + + // vtt + if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType))) { + QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy); + DelegateArgs.push_back(std::make_pair(RValue::get(VTT), VoidPP)); + + if (CGVtableInfo::needsVTTParameter(CurGD)) { + assert(I != E && "cannot skip vtt parameter, already done with args"); + assert(I->second == VoidPP && "skipping parameter not of vtt type"); + ++I; + } + } + + // Explicit arguments. + for (; I != E; ++I) { + + const VarDecl *Param = I->first; + QualType ArgType = Param->getType(); // because we're passing it to itself + + // StartFunction converted the ABI-lowered parameter(s) into a + // local alloca. We need to turn that into an r-value suitable + // for EmitCall. + llvm::Value *Local = GetAddrOfLocalVar(Param); + RValue Arg; + + // For the most part, we just need to load the alloca, except: + // 1) aggregate r-values are actually pointers to temporaries, and + // 2) references to aggregates are pointers directly to the aggregate. + // I don't know why references to non-aggregates are different here. + if (ArgType->isReferenceType()) { + const ReferenceType *RefType = ArgType->getAs<ReferenceType>(); + if (hasAggregateLLVMType(RefType->getPointeeType())) + Arg = RValue::getAggregate(Local); + else + // Locals which are references to scalars are represented + // with allocas holding the pointer. + Arg = RValue::get(Builder.CreateLoad(Local)); + } else { + if (hasAggregateLLVMType(ArgType)) + Arg = RValue::getAggregate(Local); + else + Arg = RValue::get(EmitLoadOfScalar(Local, false, ArgType)); + } + + DelegateArgs.push_back(std::make_pair(Arg, ArgType)); + } + + EmitCall(CGM.getTypes().getFunctionInfo(Ctor, CtorType), + CGM.GetAddrOfCXXConstructor(Ctor, CtorType), + ReturnValueSlot(), DelegateArgs, Ctor); +} + void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, llvm::Value *This) { @@ -1405,11 +1622,3 @@ void CodeGenFunction::InitializeVtablePtrsRecursive( // Store address point Builder.CreateStore(VtableAddressPoint, VtableField); } - -llvm::Value *CodeGenFunction::LoadCXXVTT() { - assert((isa<CXXConstructorDecl>(CurFuncDecl) || - isa<CXXDestructorDecl>(CurFuncDecl)) && - "Must be in a C++ ctor or dtor to load the vtt parameter"); - - return Builder.CreateLoad(LocalDeclMap[CXXVTTDecl], "vtt"); -} diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 5b9c6b0..0f3502e 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1034,6 +1034,28 @@ llvm::DIType CGDebugInfo::CreateType(const TagType *Ty, return llvm::DIType(); } +llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, + llvm::DICompileUnit Unit) { + llvm::DIType ElementTy = getOrCreateType(Ty->getElementType(), Unit); + uint64_t NumElems = Ty->getNumElements(); + if (NumElems > 0) + --NumElems; + llvm::SmallVector<llvm::DIDescriptor, 8> Subscripts; + Subscripts.push_back(DebugFactory.GetOrCreateSubrange(0, NumElems)); + + llvm::DIArray SubscriptArray = + DebugFactory.GetOrCreateArray(Subscripts.data(), Subscripts.size()); + + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); + + return + DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_vector_type, + Unit, "", llvm::DICompileUnit(), + 0, Size, Align, 0, 0, + ElementTy, SubscriptArray); +} + llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, llvm::DICompileUnit Unit) { uint64_t Size; @@ -1214,9 +1236,10 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, // FIXME: Handle these. case Type::ExtVector: - case Type::Vector: return llvm::DIType(); - + + case Type::Vector: + return CreateType(cast<VectorType>(Ty), Unit); case Type::ObjCObjectPointer: return CreateType(cast<ObjCObjectPointerType>(Ty), Unit); case Type::ObjCInterface: @@ -1351,10 +1374,13 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) { /// EmitRegionStart- Constructs the debug code for entering a declarative /// region - "llvm.dbg.region.start.". void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder) { + SourceManager &SM = CGM.getContext().getSourceManager(); + PresumedLoc PLoc = SM.getPresumedLoc(CurLoc); llvm::DIDescriptor D = DebugFactory.CreateLexicalBlock(RegionStack.empty() ? llvm::DIDescriptor() : - llvm::DIDescriptor(RegionStack.back())); + llvm::DIDescriptor(RegionStack.back()), + PLoc.getLine(), PLoc.getColumn()); RegionStack.push_back(D.getNode()); } @@ -1666,7 +1692,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } - llvm::StringRef DeclName = D->getName(); + llvm::StringRef DeclName = Var->getName(); llvm::DIDescriptor DContext = getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()), Unit); DebugFactory.CreateGlobalVariable(DContext, DeclName, diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index b2d3a1f..50f5759 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -84,6 +84,7 @@ class CGDebugInfo { llvm::DIType CreateType(const RecordType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const EnumType *Ty, llvm::DICompileUnit U); + llvm::DIType CreateType(const VectorType *Ty, llvm::DICompileUnit Unit); llvm::DIType CreateType(const ArrayType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DICompileUnit U); diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index d956c1c..142cb81 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -427,6 +427,26 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { } void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { + CXXTryStmtInfo Info = EnterCXXTryStmt(S); + EmitStmt(S.getTryBlock()); + ExitCXXTryStmt(S, Info); +} + +CodeGenFunction::CXXTryStmtInfo +CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S) { + CXXTryStmtInfo Info; + Info.SavedLandingPad = getInvokeDest(); + Info.HandlerBlock = createBasicBlock("try.handler"); + Info.FinallyBlock = createBasicBlock("finally"); + + PushCleanupBlock(Info.FinallyBlock); + setInvokeDest(Info.HandlerBlock); + + return Info; +} + +void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, + CXXTryStmtInfo TryInfo) { // Pointer to the personality function llvm::Constant *Personality = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty @@ -439,54 +459,12 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { llvm::Value *llvm_eh_selector = CGM.getIntrinsic(llvm::Intrinsic::eh_selector); - llvm::BasicBlock *PrevLandingPad = getInvokeDest(); - llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); - llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); + llvm::BasicBlock *PrevLandingPad = TryInfo.SavedLandingPad; + llvm::BasicBlock *TryHandler = TryInfo.HandlerBlock; + llvm::BasicBlock *FinallyBlock = TryInfo.FinallyBlock; llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); - // Push an EH context entry, used for handling rethrows. - PushCleanupBlock(FinallyBlock); - - // Emit the statements in the try {} block - setInvokeDest(TryHandler); - - // FIXME: We should not have to do this here. The AST should have the member - // initializers under the CXXTryStmt's TryBlock. - if (OuterTryBlock == &S) { - GlobalDecl GD = CurGD; - const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); - - if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { - size_t OldCleanupStackSize = CleanupEntries.size(); - EmitCtorPrologue(CD, CurGD.getCtorType()); - EmitStmt(S.getTryBlock()); - - // If any of the member initializers are temporaries bound to references - // make sure to emit their destructors. - EmitCleanupBlocks(OldCleanupStackSize); - } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) { - llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); - PushCleanupBlock(DtorEpilogue); - - InitializeVtablePtrs(DD->getParent()); - EmitStmt(S.getTryBlock()); - - CleanupBlockInfo Info = PopCleanupBlock(); - - assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!"); - EmitBlock(DtorEpilogue); - EmitDtorEpilogue(DD, GD.getDtorType()); - - if (Info.SwitchBlock) - EmitBlock(Info.SwitchBlock); - if (Info.EndBlock) - EmitBlock(Info.EndBlock); - } else - EmitStmt(S.getTryBlock()); - } else - EmitStmt(S.getTryBlock()); - // Jump to end if there is no exception EmitBranchThroughCleanup(FinallyEnd); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 830954f..030d2c9 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -36,7 +36,17 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty, return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt); } -llvm::Value *CodeGenFunction::CreateMemTemp(QualType Ty, const llvm::Twine &Name) { +llvm::Value *CodeGenFunction::CreateIRTemp(QualType Ty, + const llvm::Twine &Name) { + llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertType(Ty), Name); + // FIXME: Should we prefer the preferred type alignment here? + CharUnits Align = getContext().getTypeAlignInChars(Ty); + Alloc->setAlignment(Align.getQuantity()); + return Alloc; +} + +llvm::Value *CodeGenFunction::CreateMemTemp(QualType Ty, + const llvm::Twine &Name) { llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty), Name); // FIXME: Should we prefer the preferred type alignment here? CharUnits Align = getContext().getTypeAlignInChars(Ty); @@ -1520,9 +1530,7 @@ CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value* BaseValue, } LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){ - llvm::Value *DeclPtr = CreateTempAlloca(ConvertTypeForMem(E->getType()), - ".compoundliteral"); - + llvm::Value *DeclPtr = CreateMemTemp(E->getType(), ".compoundliteral"); const Expr* InitExpr = E->getInitializer(); LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType())); diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 97455c7..ac189a0 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -189,7 +189,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { CGF.ConvertType(PtrTy)); EmitInitializationToLValue(E->getSubExpr(), LValue::MakeAddr(CastPtr, Qualifiers()), - E->getType()); + E->getSubExpr()->getType()); break; } diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 1d38ef9..198e2d1 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -56,7 +56,7 @@ private: const llvm::FunctionType *IMPTy; const llvm::PointerType *IdTy; const llvm::PointerType *PtrToIdTy; - QualType ASTIdTy; + CanQualType ASTIdTy; const llvm::IntegerType *IntTy; const llvm::PointerType *PtrTy; const llvm::IntegerType *LongTy; @@ -262,7 +262,7 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) PtrTy = PtrToInt8Ty; // Object type - ASTIdTy = CGM.getContext().getObjCIdType(); + ASTIdTy = CGM.getContext().getCanonicalType(CGM.getContext().getObjCIdType()); if (QualType() == ASTIdTy) { IdTy = PtrToInt8Ty; } else { @@ -1192,19 +1192,22 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI iter != endIter ; iter++) { std::vector<llvm::Constant*> Fields; ObjCPropertyDecl *property = (*iter)->getPropertyDecl(); + ObjCPropertyImplDecl *propertyImpl = *iter; + bool isSynthesized = (propertyImpl->getPropertyImplementation() == + ObjCPropertyImplDecl::Synthesize); Fields.push_back(MakeConstantString(property->getNameAsString())); Fields.push_back(llvm::ConstantInt::get(Int8Ty, property->getPropertyAttributes())); - Fields.push_back(llvm::ConstantInt::get(Int8Ty, - (*iter)->getPropertyImplementation() == - ObjCPropertyImplDecl::Synthesize)); + Fields.push_back(llvm::ConstantInt::get(Int8Ty, isSynthesized)); if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) { - InstanceMethodSels.push_back(getter->getSelector()); std::string TypeStr; Context.getObjCEncodingForMethodDecl(getter,TypeStr); llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); - InstanceMethodTypes.push_back(TypeEncoding); + if (isSynthesized) { + InstanceMethodTypes.push_back(TypeEncoding); + InstanceMethodSels.push_back(getter->getSelector()); + } Fields.push_back(MakeConstantString(getter->getSelector().getAsString())); Fields.push_back(TypeEncoding); } else { @@ -1212,11 +1215,13 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI Fields.push_back(NULLPtr); } if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) { - InstanceMethodSels.push_back(setter->getSelector()); std::string TypeStr; Context.getObjCEncodingForMethodDecl(setter,TypeStr); llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); - InstanceMethodTypes.push_back(TypeEncoding); + if (isSynthesized) { + InstanceMethodTypes.push_back(TypeEncoding); + InstanceMethodSels.push_back(setter->getSelector()); + } Fields.push_back(MakeConstantString(setter->getSelector().getAsString())); Fields.push_back(TypeEncoding); } else { @@ -1685,7 +1690,7 @@ llvm::Constant *CGObjCGNU::EnumerationMutationFunction() { CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); // void objc_enumerationMutation (id) - llvm::SmallVector<QualType,16> Params; + llvm::SmallVector<CanQualType,1> Params; Params.push_back(ASTIdTy); const llvm::FunctionType *FTy = Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index b16a510..475280b 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -297,9 +297,9 @@ public: CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); // id objc_getProperty (id, SEL, ptrdiff_t, bool) - llvm::SmallVector<QualType,16> Params; - QualType IdType = Ctx.getObjCIdType(); - QualType SelType = Ctx.getObjCSelType(); + llvm::SmallVector<CanQualType,4> Params; + CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType()); + CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType()); Params.push_back(IdType); Params.push_back(SelType); Params.push_back(Ctx.LongTy); @@ -314,9 +314,9 @@ public: CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool) - llvm::SmallVector<QualType,16> Params; - QualType IdType = Ctx.getObjCIdType(); - QualType SelType = Ctx.getObjCSelType(); + llvm::SmallVector<CanQualType,6> Params; + CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType()); + CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType()); Params.push_back(IdType); Params.push_back(SelType); Params.push_back(Ctx.LongTy); @@ -333,8 +333,8 @@ public: CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); // void objc_enumerationMutation (id) - llvm::SmallVector<QualType,16> Params; - Params.push_back(Ctx.getObjCIdType()); + llvm::SmallVector<CanQualType,1> Params; + Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType())); const llvm::FunctionType *FTy = Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, CC_Default, false), false); @@ -3293,7 +3293,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( // Add this implementations synthesized ivars. llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; - CGM.getContext().CollectSynthesizedIvars(OI, Ivars); + CGM.getContext().CollectNonClassIvars(OI, Ivars); for (unsigned k = 0, e = Ivars.size(); k != e; ++k) RecFields.push_back(cast<FieldDecl>(Ivars[k])); @@ -5093,9 +5093,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( // Find the message function name. // FIXME. This is too much work to get the ABI-specific result type needed to // find the message name. - const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, - llvm::SmallVector<QualType, 16>(), - CC_Default, false); + const CGFunctionInfo &FnInfo + = Types.getFunctionInfo(ResultType, CallArgList(), CC_Default, false); llvm::Constant *Fn = 0; std::string Name("\01l_"); if (CGM.ReturnTypeUsesSret(FnInfo)) { diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp index 9714bd9..96c104b 100644 --- a/lib/CodeGen/CGVTT.cpp +++ b/lib/CodeGen/CGVTT.cpp @@ -46,7 +46,8 @@ class VTTBuilder { llvm::DenseMap<std::pair<const CXXRecordDecl *, BaseSubobject>, uint64_t> CtorVtableAddressPoints; - llvm::Constant *getCtorVtable(const BaseSubobject &Base) { + llvm::Constant *getCtorVtable(const BaseSubobject &Base, + bool BaseIsVirtual) { if (!GenerateDefinition) return 0; @@ -54,7 +55,7 @@ class VTTBuilder { if (!CtorVtable) { // Build the vtable. CGVtableInfo::CtorVtableInfo Info - = CGM.getVtableInfo().getCtorVtable(Class, Base); + = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseIsVirtual); CtorVtable = Info.Vtable; @@ -166,7 +167,7 @@ class VTTBuilder { if (BaseMorallyVirtual || VtblClass == Class) init = BuildVtablePtr(vtbl, VtblClass, Base, BaseOffset); else { - init = getCtorVtable(BaseSubobject(Base, BaseOffset)); + init = getCtorVtable(BaseSubobject(Base, BaseOffset), i->isVirtual()); subvtbl = init; subVtblClass = Base; @@ -186,7 +187,8 @@ class VTTBuilder { /// BuiltVTT - Add the VTT to Inits. Offset is the offset in bits to the /// currnet object we're working on. - void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool MorallyVirtual) { + void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool BaseIsVirtual, + bool MorallyVirtual) { // Itanium C++ ABI 2.6.2: // An array of virtual table addresses, called the VTT, is declared for // each class type that has indirect or direct virtual base classes. @@ -204,7 +206,8 @@ class VTTBuilder { Vtable = ClassVtbl; VtableClass = Class; } else { - Vtable = getCtorVtable(BaseSubobject(RD, Offset)); + Vtable = getCtorVtable(BaseSubobject(RD, Offset), + /*IsVirtual=*/BaseIsVirtual); VtableClass = RD; } @@ -235,7 +238,7 @@ class VTTBuilder { const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base); - BuildVTT(Base, BaseOffset, MorallyVirtual); + BuildVTT(Base, BaseOffset, /*BaseIsVirtual=*/false, MorallyVirtual); } } @@ -249,7 +252,7 @@ class VTTBuilder { if (i->isVirtual() && !SeenVBase.count(Base)) { SeenVBase.insert(Base); uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base); - BuildVTT(Base, BaseOffset, false); + BuildVTT(Base, BaseOffset, /*BaseIsVirtual=*/true, false); } VirtualVTTs(Base); } @@ -335,13 +338,13 @@ CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, CGVtableInfo::CtorVtableInfo CGVtableInfo::getCtorVtable(const CXXRecordDecl *RD, - const BaseSubobject &Base) { + const BaseSubobject &Base, bool BaseIsVirtual) { CtorVtableInfo Info; Info.Vtable = GenerateVtable(llvm::GlobalValue::InternalLinkage, /*GenerateDefinition=*/true, RD, Base.getBase(), Base.getBaseOffset(), - Info.AddressPoints); + BaseIsVirtual, Info.AddressPoints); return Info; } diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 970bbd7..932bd07 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -16,6 +16,7 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/RecordLayout.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" #include <cstdio> @@ -25,40 +26,44 @@ using namespace CodeGen; namespace { +/// BaseOffset - Represents an offset from a derived class to a direct or +/// indirect base class. +struct BaseOffset { + /// DerivedClass - The derived class. + const CXXRecordDecl *DerivedClass; + + /// VirtualBase - If the path from the derived class to the base class + /// involves a virtual base class, this holds its declaration. + const CXXRecordDecl *VirtualBase; + + /// NonVirtualOffset - The offset from the derived class to the base class. + /// (Or the offset from the virtual base class to the base class, if the + /// path from the derived class to the base class involves a virtual base + /// class. + int64_t NonVirtualOffset; + + BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { } + BaseOffset(const CXXRecordDecl *DerivedClass, + const CXXRecordDecl *VirtualBase, int64_t NonVirtualOffset) + : DerivedClass(DerivedClass), VirtualBase(VirtualBase), + NonVirtualOffset(NonVirtualOffset) { } + + bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; } +}; + /// FinalOverriders - Contains the final overrider member functions for all /// member functions in the base subobjects of a class. class FinalOverriders { public: - /// BaseOffset - Represents an offset from a derived class to a direct or - /// indirect base class. - struct BaseOffset { - /// DerivedClass - The derived class. - const CXXRecordDecl *DerivedClass; - - /// VirtualBase - If the path from the derived class to the base class - /// involves a virtual base class, this holds its declaration. - const CXXRecordDecl *VirtualBase; - - /// NonVirtualOffset - The offset from the derived class to the base class. - /// Or the offset from the virtual base class to the base class, if the path - /// from the derived class to the base class involves a virtual base class. - int64_t NonVirtualOffset; - - BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { } - BaseOffset(const CXXRecordDecl *DerivedClass, - const CXXRecordDecl *VirtualBase, int64_t NonVirtualOffset) - : DerivedClass(DerivedClass), VirtualBase(VirtualBase), - NonVirtualOffset(NonVirtualOffset) { } - - bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; } - }; - /// OverriderInfo - Information about a final overrider. struct OverriderInfo { /// Method - The method decl of the overrider. const CXXMethodDecl *Method; + + /// Offset - the base offset of the overrider relative to the layout class. + int64_t Offset; - OverriderInfo() : Method(0) { } + OverriderInfo() : Method(0), Offset(0) { } }; private: @@ -93,12 +98,9 @@ private: /// ReturnAdjustments - Holds return adjustments for all the overriders that /// need to perform return value adjustments. AdjustmentOffsetsMapTy ReturnAdjustments; - - /// ThisAdjustments - Holds 'this' adjustments for all the overriders that - /// need them. - AdjustmentOffsetsMapTy ThisAdjustments; - typedef llvm::SmallVector<uint64_t, 1> OffsetVectorTy; + // FIXME: We might be able to get away with making this a SmallSet. + typedef llvm::SmallSetVector<uint64_t, 2> OffsetSetVectorTy; /// SubobjectOffsetsMapTy - This map is used for keeping track of all the /// base subobject offsets that a single class declaration might refer to. @@ -113,12 +115,13 @@ private: /// when we determine that C::f() overrides A::f(), we need to update the /// overriders map for both A-in-B1 and A-in-B2 and the subobject offsets map /// will have the subobject offsets for both A copies. - typedef llvm::DenseMap<const CXXRecordDecl *, OffsetVectorTy> + typedef llvm::DenseMap<const CXXRecordDecl *, OffsetSetVectorTy> SubobjectOffsetsMapTy; /// ComputeFinalOverriders - Compute the final overriders for a given base /// subobject (and all its direct and indirect bases). void ComputeFinalOverriders(BaseSubobject Base, + bool BaseSubobjectIsVisitedVBase, SubobjectOffsetsMapTy &Offsets); /// AddOverriders - Add the final overriders for this base subobject to the @@ -139,17 +142,12 @@ private: const CXXMethodDecl *NewMD, SubobjectOffsetsMapTy &Offsets); - /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting - /// the 'this' pointer from the base subobject to the derived subobject. - BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base, - BaseSubobject Derived); - static void MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets, SubobjectOffsetsMapTy &Offsets); public: explicit FinalOverriders(const CXXRecordDecl *MostDerivedClass); - + /// getOverrider - Get the final overrider for the given method declaration in /// the given base subobject. OverriderInfo getOverrider(BaseSubobject Base, @@ -168,14 +166,6 @@ public: return ReturnAdjustments.lookup(std::make_pair(Base, MD)); } - /// getThisAdjustmentOffset - Get the 'this' pointer adjustment offset for the - /// method decl in the given base subobject. Returns an empty base offset if - /// no adjustment is needed. - BaseOffset getThisAdjustmentOffset(BaseSubobject Base, - const CXXMethodDecl *MD) const { - return ThisAdjustments.lookup(std::make_pair(Base, MD)); - } - /// dump - dump the final overriders. void dump() { assert(VisitedVirtualBases.empty() && @@ -189,6 +179,8 @@ public: void dump(llvm::raw_ostream &Out, BaseSubobject Base); }; +#define DUMP_OVERRIDERS 0 + FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass) : MostDerivedClass(MostDerivedClass), Context(MostDerivedClass->getASTContext()), @@ -196,8 +188,11 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass) // Compute the final overriders. SubobjectOffsetsMapTy Offsets; - ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0), Offsets); - + ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0), + /*BaseSubobjectIsVisitedVBase=*/false, Offsets); + VisitedVirtualBases.clear(); + +#if DUMP_OVERRIDERS // And dump them (for now). dump(); @@ -212,6 +207,7 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass) for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) llvm::errs() << " " << I << " - " << OffsetVector[I] << '\n'; } +#endif } void FinalOverriders::AddOverriders(BaseSubobject Base, @@ -232,13 +228,14 @@ void FinalOverriders::AddOverriders(BaseSubobject Base, OverriderInfo& Overrider = OverridersMap[std::make_pair(Base, MD)]; assert(!Overrider.Method && "Overrider should not exist yet!"); + Overrider.Offset = Base.getBaseOffset(); Overrider.Method = MD; } } -static FinalOverriders::BaseOffset -ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *DerivedRD, - const CXXBasePath &Path) { +static BaseOffset ComputeBaseOffset(ASTContext &Context, + const CXXRecordDecl *DerivedRD, + const CXXBasePath &Path) { int64_t NonVirtualOffset = 0; unsigned NonVirtualStart = 0; @@ -264,37 +261,36 @@ ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *DerivedRD, // Check the base class offset. const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); - + const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>(); const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl()); - + NonVirtualOffset += Layout.getBaseClassOffset(Base); } // FIXME: This should probably use CharUnits or something. Maybe we should // even change the base offsets in ASTRecordLayout to be specified in // CharUnits. - return FinalOverriders::BaseOffset(DerivedRD, VirtualBase, - NonVirtualOffset / 8); + return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset / 8); } -static FinalOverriders::BaseOffset -ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *BaseRD, - const CXXRecordDecl *DerivedRD) { +static BaseOffset ComputeBaseOffset(ASTContext &Context, + const CXXRecordDecl *BaseRD, + const CXXRecordDecl *DerivedRD) { CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, /*DetectVirtual=*/false); if (!const_cast<CXXRecordDecl *>(DerivedRD)-> isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) { assert(false && "Class must be derived from the passed in base class!"); - return FinalOverriders::BaseOffset(); + return BaseOffset(); } return ComputeBaseOffset(Context, DerivedRD, Paths.front()); } -static FinalOverriders::BaseOffset +static BaseOffset ComputeReturnAdjustmentBaseOffset(ASTContext &Context, const CXXMethodDecl *DerivedMD, const CXXMethodDecl *BaseMD) { @@ -313,7 +309,7 @@ ComputeReturnAdjustmentBaseOffset(ASTContext &Context, if (CanDerivedReturnType == CanBaseReturnType) { // No adjustment needed. - return FinalOverriders::BaseOffset(); + return BaseOffset(); } if (isa<ReferenceType>(CanDerivedReturnType)) { @@ -336,7 +332,7 @@ ComputeReturnAdjustmentBaseOffset(ASTContext &Context, if (CanDerivedReturnType.getUnqualifiedType() == CanBaseReturnType.getUnqualifiedType()) { // No adjustment needed. - return FinalOverriders::BaseOffset(); + return BaseOffset(); } const CXXRecordDecl *DerivedRD = @@ -348,35 +344,6 @@ ComputeReturnAdjustmentBaseOffset(ASTContext &Context, return ComputeBaseOffset(Context, BaseRD, DerivedRD); } -FinalOverriders::BaseOffset -FinalOverriders::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, - BaseSubobject Derived) { - const CXXRecordDecl *BaseRD = Base.getBase(); - const CXXRecordDecl *DerivedRD = Derived.getBase(); - - CXXBasePaths Paths(/*FindAmbiguities=*/true, - /*RecordPaths=*/true, /*DetectVirtual=*/true); - - if (!const_cast<CXXRecordDecl *>(DerivedRD)-> - isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return FinalOverriders::BaseOffset(); - } - - assert(!Paths.getDetectedVirtual() && "FIXME: Handle virtual bases!"); - - BaseOffset Offset; - - // FIXME: This is not going to be enough with virtual bases. - // FIXME: We should not use / 8 here. - int64_t DerivedToBaseOffset = - (Base.getBaseOffset() - Derived.getBaseOffset()) / 8; - - Offset.NonVirtualOffset = -DerivedToBaseOffset; - - return Offset; -} - void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD, BaseSubobject NewBase, const CXXMethodDecl *NewMD, @@ -394,7 +361,7 @@ void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD, /// struct C : B1, B2 { virtual void f(); }; /// /// When overriding A::f with C::f we need to do so in both A subobjects. - const OffsetVectorTy &OffsetVector = Offsets[OverriddenRD]; + const OffsetSetVectorTy &OffsetVector = Offsets[OverriddenRD]; // Go through all the subobjects. for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) { @@ -419,20 +386,10 @@ void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD, // Store the return adjustment base offset. ReturnAdjustments[SubobjectAndMethod] = ReturnBaseOffset; } - - // Check if we need a 'this' adjustment base offset as well. - if (Offset != NewBase.getBaseOffset()) { - BaseOffset ThisBaseOffset = - ComputeThisAdjustmentBaseOffset(OverriddenSubobject, - NewBase); - assert(!ThisBaseOffset.isEmpty() && - "Should not get an empty 'this' adjustment!"); - - ThisAdjustments[SubobjectAndMethod] = ThisBaseOffset; - } } // Set the new overrider. + Overrider.Offset = NewBase.getBaseOffset(); Overrider.Method = NewMD; // And propagate it further. @@ -448,45 +405,17 @@ FinalOverriders::MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets, for (SubobjectOffsetsMapTy::const_iterator I = NewOffsets.begin(), E = NewOffsets.end(); I != E; ++I) { const CXXRecordDecl *NewRD = I->first; - const OffsetVectorTy& NewOffsetVector = I->second; - - OffsetVectorTy &OffsetVector = Offsets[NewRD]; - if (OffsetVector.empty()) { - // There were no previous offsets in this vector, just insert all entries - // from the new offset vector. - OffsetVector.append(NewOffsetVector.begin(), NewOffsetVector.end()); - continue; - } - - // We need to merge the new offsets vector into the old, but we don't want - // to have duplicate entries. Do this by inserting the old offsets in a set - // so they'll be unique. After this, we iterate over the new offset vector - // and only append elements that aren't in the set. + const OffsetSetVectorTy& NewOffsetVector = I->second; - // First, add the existing offsets to the set. - llvm::SmallSet<uint64_t, 4> OffsetSet; - for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) { - bool Inserted = OffsetSet.insert(OffsetVector[I]); - if (!Inserted) - assert(false && "Set of offsets should be unique!"); - } + OffsetSetVectorTy &OffsetVector = Offsets[NewRD]; - // Next, only add the new offsets if they are not already in the set. - for (unsigned I = 0, E = NewOffsetVector.size(); I != E; ++I) { - uint64_t Offset = NewOffsetVector[I]; - - if (OffsetSet.count(Offset)) { - // Ignore the offset. - continue; - } - - // Otherwise, add it to the offsets vector. - OffsetVector.push_back(Offset); - } + // Merge the new offsets set vector into the old. + OffsetVector.insert(NewOffsetVector.begin(), NewOffsetVector.end()); } } void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base, + bool BaseSubobjectIsVisitedVBase, SubobjectOffsetsMapTy &Offsets) { const CXXRecordDecl *RD = Base.getBase(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); @@ -502,25 +431,51 @@ void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base, if (!BaseDecl->isPolymorphic()) continue; + bool IsVisitedVirtualBase = BaseSubobjectIsVisitedVBase; uint64_t BaseOffset; if (I->isVirtual()) { + if (!VisitedVirtualBases.insert(BaseDecl)) + IsVisitedVirtualBase = true; BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); } else { BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset(); } // Compute the final overriders for this base. - ComputeFinalOverriders(BaseSubobject(BaseDecl, BaseOffset), NewOffsets); + // We always want to compute the final overriders, even if the base is a + // visited virtual base. Consider: + // + // struct A { + // virtual void f(); + // virtual void g(); + // }; + // + // struct B : virtual A { + // void f(); + // }; + // + // struct C : virtual A { + // void g (); + // }; + // + // struct D : B, C { }; + // + // Here, we still want to compute the overriders for A as a base of C, + // because otherwise we'll miss that C::g overrides A::f. + ComputeFinalOverriders(BaseSubobject(BaseDecl, BaseOffset), + IsVisitedVirtualBase, NewOffsets); } /// Now add the overriders for this particular subobject. - AddOverriders(Base, NewOffsets); + /// (We don't want to do this more than once for a virtual base). + if (!BaseSubobjectIsVisitedVBase) + AddOverriders(Base, NewOffsets); // And merge the newly discovered subobject offsets. MergeSubobjectOffsets(NewOffsets, Offsets); /// Finally, add the offset for our own subobject. - Offsets[RD].push_back(Base.getBaseOffset()); + Offsets[RD].insert(Base.getBaseOffset()); } void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) { @@ -565,9 +520,10 @@ void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) { OverriderInfo Overrider = getOverrider(Base, MD); - Out << " " << MD->getQualifiedNameAsString() << " - "; + Out << " " << MD->getQualifiedNameAsString() << " - ("; Out << Overrider.Method->getQualifiedNameAsString(); - + Out << ", " << Overrider.Offset << ')'; + AdjustmentOffsetsMapTy::const_iterator AI = ReturnAdjustments.find(std::make_pair(Base, MD)); if (AI != ReturnAdjustments.end()) { @@ -580,17 +536,6 @@ void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) { Out << Offset.NonVirtualOffset << " nv]"; } - AI = ThisAdjustments.find(std::make_pair(Base, MD)); - if (AI != ThisAdjustments.end()) { - const BaseOffset &Offset = AI->second; - - Out << " [this-adj: "; - if (Offset.VirtualBase) - Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, "; - - Out << Offset.NonVirtualOffset << " nv]"; - } - Out << "\n"; } } @@ -609,9 +554,18 @@ public: CK_CompleteDtorPointer, /// CK_DeletingDtorPointer - A pointer to the deleting destructor. - CK_DeletingDtorPointer + CK_DeletingDtorPointer, + + /// CK_UnusedFunctionPointer - In some cases, a vtable function pointer + /// will end up never being called. Such vtable function pointers are + /// represented as a CK_UnusedFunctionPointer. + CK_UnusedFunctionPointer }; + static VtableComponent MakeVCallOffset(int64_t Offset) { + return VtableComponent(CK_VCallOffset, Offset); + } + static VtableComponent MakeVBaseOffset(int64_t Offset) { return VtableComponent(CK_VBaseOffset, Offset); } @@ -642,11 +596,24 @@ public: reinterpret_cast<uintptr_t>(DD)); } + static VtableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { + assert(!isa<CXXDestructorDecl>(MD) && + "Don't use MakeUnusedFunction with destructors!"); + return VtableComponent(CK_UnusedFunctionPointer, + reinterpret_cast<uintptr_t>(MD)); + } + /// getKind - Get the kind of this vtable component. Kind getKind() const { return (Kind)(Value & 0x7); } + int64_t getVCallOffset() const { + assert(getKind() == CK_VCallOffset && "Invalid component kind!"); + + return getOffset(); + } + int64_t getVBaseOffset() const { assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); @@ -678,6 +645,12 @@ public: return reinterpret_cast<CXXDestructorDecl *>(getPointer()); } + const CXXMethodDecl *getUnusedFunctionDecl() const { + assert(getKind() == CK_UnusedFunctionPointer); + + return reinterpret_cast<CXXMethodDecl *>(getPointer()); + } + private: VtableComponent(Kind ComponentKind, int64_t Offset) { assert((ComponentKind == CK_VCallOffset || @@ -692,7 +665,8 @@ private: assert((ComponentKind == CK_RTTI || ComponentKind == CK_FunctionPointer || ComponentKind == CK_CompleteDtorPointer || - ComponentKind == CK_DeletingDtorPointer) && + ComponentKind == CK_DeletingDtorPointer || + ComponentKind == CK_UnusedFunctionPointer) && "Invalid component kind!"); assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!"); @@ -711,7 +685,8 @@ private: assert((getKind() == CK_RTTI || getKind() == CK_FunctionPointer || getKind() == CK_CompleteDtorPointer || - getKind() == CK_DeletingDtorPointer) && + getKind() == CK_DeletingDtorPointer || + getKind() == CK_UnusedFunctionPointer) && "Invalid component kind!"); return static_cast<uintptr_t>(Value & ~7ULL); @@ -725,12 +700,334 @@ private: int64_t Value; }; +/// VCallOffsetMap - Keeps track of vcall offsets when building a vtable. +struct VCallOffsetMap { + + typedef std::pair<const CXXMethodDecl *, int64_t> MethodAndOffsetPairTy; + + /// Offsets - Keeps track of methods and their offsets. + // FIXME: This should be a real map and not a vector. + llvm::SmallVector<MethodAndOffsetPairTy, 16> Offsets; + + /// MethodsCanShareVCallOffset - Returns whether two virtual member functions + /// can share the same vcall offset. + static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS); + +public: + /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the + /// add was successful, or false if there was already a member function with + /// the same signature in the map. + bool AddVCallOffset(const CXXMethodDecl *MD, int64_t OffsetOffset); + + /// getVCallOffsetOffset - Returns the vcall offset offset (relative to the + /// vtable address point) for the given virtual member function. + int64_t getVCallOffsetOffset(const CXXMethodDecl *MD); + + // empty - Return whether the offset map is empty or not. + bool empty() const { return Offsets.empty(); } +}; + +static bool HasSameVirtualSignature(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS) { + ASTContext &C = LHS->getASTContext(); // TODO: thread this down + CanQual<FunctionProtoType> + LT = C.getCanonicalType(LHS->getType()).getAs<FunctionProtoType>(), + RT = C.getCanonicalType(RHS->getType()).getAs<FunctionProtoType>(); + + // Fast-path matches in the canonical types. + if (LT == RT) return true; + + // Force the signatures to match. We can't rely on the overrides + // list here because there isn't necessarily an inheritance + // relationship between the two methods. + if (LT.getQualifiers() != RT.getQualifiers() || + LT->getNumArgs() != RT->getNumArgs()) + return false; + for (unsigned I = 0, E = LT->getNumArgs(); I != E; ++I) + if (LT->getArgType(I) != RT->getArgType(I)) + return false; + return true; +} + +bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS) { + assert(LHS->isVirtual() && "LHS must be virtual!"); + assert(RHS->isVirtual() && "LHS must be virtual!"); + + // A destructor can share a vcall offset with another destructor. + if (isa<CXXDestructorDecl>(LHS)) + return isa<CXXDestructorDecl>(RHS); + + // FIXME: We need to check more things here. + + // The methods must have the same name. + DeclarationName LHSName = LHS->getDeclName(); + DeclarationName RHSName = RHS->getDeclName(); + if (LHSName != RHSName) + return false; + + // And the same signatures. + return HasSameVirtualSignature(LHS, RHS); +} + +bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD, + int64_t OffsetOffset) { + // Check if we can reuse an offset. + for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { + if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) + return false; + } + + // Add the offset. + Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset)); + return true; +} + +int64_t VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { + // Look for an offset. + for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { + if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) + return Offsets[I].second; + } + + assert(false && "Should always find a vcall offset offset!"); + return 0; +} + +/// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets. +class VCallAndVBaseOffsetBuilder { + /// MostDerivedClass - The most derived class for which we're building vcall + /// and vbase offsets. + const CXXRecordDecl *MostDerivedClass; + + /// LayoutClass - The class we're using for layout information. Will be + /// different than the most derived class if we're building a construction + /// vtable. + const CXXRecordDecl *LayoutClass; + + /// Context - The ASTContext which we will use for layout information. + ASTContext &Context; + + /// Components - vcall and vbase offset components + typedef llvm::SmallVector<VtableComponent, 64> VtableComponentVectorTy; + VtableComponentVectorTy Components; + + /// VisitedVirtualBases - Visited virtual bases. + llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases; + + /// VCallOffsets - Keeps track of vcall offsets. + VCallOffsetMap VCallOffsets; + + /// FinalOverriders - The final overriders of the most derived class. + /// (Can be null when we're not building a vtable of the most derived class). + const FinalOverriders *Overriders; + + /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the + /// given base subobject. + void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, + uint64_t RealBaseOffset); + + /// AddVCallOffsets - Add vcall offsets for the given base subobject. + void AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset); + + /// AddVBaseOffsets - Add vbase offsets for the given class. + void AddVBaseOffsets(const CXXRecordDecl *Base, uint64_t OffsetInLayoutClass); + +public: + VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass, + const CXXRecordDecl *LayoutClass, + const FinalOverriders *Overriders, + BaseSubobject Base, bool BaseIsVirtual, + uint64_t OffsetInLayoutClass) + : MostDerivedClass(MostDerivedClass), LayoutClass(LayoutClass), + Context(MostDerivedClass->getASTContext()), Overriders(Overriders) { + + // Add vcall and vbase offsets. + AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass); + } + + /// Methods for iterating over the components. + typedef VtableComponentVectorTy::const_reverse_iterator const_iterator; + const_iterator components_begin() const { return Components.rbegin(); } + const_iterator components_end() const { return Components.rend(); } + + const VCallOffsetMap& getVCallOffsets() const { return VCallOffsets; } +}; + +void +VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, + bool BaseIsVirtual, + uint64_t RealBaseOffset) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); + + // Itanium C++ ABI 2.5.2: + // ..in classes sharing a virtual table with a primary base class, the vcall + // and vbase offsets added by the derived class all come before the vcall + // and vbase offsets required by the base class, so that the latter may be + // laid out as required by the base class without regard to additions from + // the derived class(es). + + // (Since we're emitting the vcall and vbase offsets in reverse order, we'll + // emit them for the primary base first). + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + bool PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual(); + + uint64_t PrimaryBaseOffset; + + // Get the base offset of the primary base. + if (PrimaryBaseIsVirtual) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + PrimaryBaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + PrimaryBaseOffset = Base.getBaseOffset(); + } + + AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), + PrimaryBaseIsVirtual, RealBaseOffset); + } + + AddVBaseOffsets(Base.getBase(), RealBaseOffset); + + // We only want to add vcall offsets for virtual bases. + if (BaseIsVirtual) + AddVCallOffsets(Base, RealBaseOffset); +} + +void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, + uint64_t VBaseOffset) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + // Handle the primary base first. + if (PrimaryBase) { + uint64_t PrimaryBaseOffset; + + // Get the base offset of the primary base. + if (Layout.getPrimaryBaseWasVirtual()) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + PrimaryBaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + PrimaryBaseOffset = Base.getBaseOffset(); + } + + AddVCallOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), + VBaseOffset); + } + + // Add the vcall offsets. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + // OffsetIndex is the index of this vcall offset, relative to the vtable + // address point. (We subtract 3 to account for the information just + // above the address point, the RTTI info, the offset to top, and the + // vcall offset itself). + int64_t OffsetIndex = -(int64_t)(3 + Components.size()); + + // FIXME: We shouldn't use / 8 here. + int64_t OffsetOffset = OffsetIndex * + (int64_t)Context.Target.getPointerWidth(0) / 8; + + // Don't add a vcall offset if we already have one for this member function + // signature. + if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) + continue; + + int64_t Offset = 0; + + if (Overriders) { + // Get the final overrider. + FinalOverriders::OverriderInfo Overrider = + Overriders->getOverrider(Base, MD); + + /// The vcall offset is the offset from the virtual base to the object + /// where the function was overridden. + // FIXME: We should not use / 8 here. + Offset = (int64_t)(Overrider.Offset - VBaseOffset) / 8; + } + + Components.push_back(VtableComponent::MakeVCallOffset(Offset)); + } + + // And iterate over all non-virtual bases (ignoring the primary base). + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + if (BaseDecl == PrimaryBase) + continue; + + // Get the base offset of this base. + uint64_t BaseOffset = Base.getBaseOffset() + + Layout.getBaseClassOffset(BaseDecl); + + AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), VBaseOffset); + } +} + +void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, + uint64_t OffsetInLayoutClass) { + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + // Add vbase offsets. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Check if this is a virtual base that we haven't visited before. + if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) { + // FIXME: We shouldn't use / 8 here. + int64_t Offset = + (int64_t)(LayoutClassLayout.getVBaseClassOffset(BaseDecl) - + OffsetInLayoutClass) / 8; + + Components.push_back(VtableComponent::MakeVBaseOffset(Offset)); + } + + // Check the base class looking for more vbase offsets. + AddVBaseOffsets(BaseDecl, OffsetInLayoutClass); + } +} + /// VtableBuilder - Class for building vtable layout information. class VtableBuilder { public: - /// PrimaryBasesSetTy - A set of direct and indirect primary bases. - typedef llvm::SmallPtrSet<const CXXRecordDecl *, 8> PrimaryBasesSetTy; - + /// PrimaryBasesSetVectorTy - A set vector of direct and indirect + /// primary bases. + typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> + PrimaryBasesSetVectorTy; + private: /// VtableInfo - Global vtable information. CGVtableInfo &VtableInfo; @@ -739,15 +1036,28 @@ private: /// vtable. const CXXRecordDecl *MostDerivedClass; + /// MostDerivedClassOffset - If we're building a construction vtable, this + /// holds the offset from the layout class to the most derived class. + const uint64_t MostDerivedClassOffset; + + /// MostDerivedClassIsVirtual - Whether the most derived class is a virtual + /// base. (This only makes sense when building a construction vtable). + bool MostDerivedClassIsVirtual; + + /// LayoutClass - The class we're using for layout information. Will be + /// different than the most derived class if we're building a construction + /// vtable. + const CXXRecordDecl *LayoutClass; + /// Context - The ASTContext which we will use for layout information. ASTContext &Context; /// FinalOverriders - The final overriders of the most derived class. - FinalOverriders Overriders; + const FinalOverriders Overriders; - /// VCallAndVBaseOffsets - The vcall and vbase offset, of the vtable we're - // building (in reverse order). - llvm::SmallVector<VtableComponent, 64> VCallAndVBaseOffsets; + /// VCallOffsetsForVBases - Keeps track of vcall offsets for the virtual + /// bases in this vtable. + llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases; /// Components - The components of the vtable being built. llvm::SmallVector<VtableComponent, 64> Components; @@ -761,7 +1071,7 @@ private: /// nearest virtual base. int64_t NonVirtual; - /// VBaseOffsetOffset - The offset, in bytes, relative to the address point + /// VBaseOffsetOffset - The offset (in bytes), relative to the address point /// of the virtual base class offset. int64_t VBaseOffsetOffset; @@ -774,72 +1084,159 @@ private: llvm::SmallVector<std::pair<uint64_t, ReturnAdjustment>, 16> ReturnAdjustments; + /// MethodInfo - Contains information about a method in a vtable. + /// (Used for computing 'this' pointer adjustment thunks. + struct MethodInfo { + /// BaseOffset - The base offset of this method. + const uint64_t BaseOffset; + + /// VtableIndex - The index in the vtable that this method has. + /// (For destructors, this is the index of the complete destructor). + const uint64_t VtableIndex; + + MethodInfo(uint64_t BaseOffset, uint64_t VtableIndex) + : BaseOffset(BaseOffset), VtableIndex(VtableIndex) { } + + MethodInfo() : BaseOffset(0), VtableIndex(0) { } + }; + + typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; + + /// MethodInfoMap - The information for all methods in the vtable we're + /// currently building. + MethodInfoMapTy MethodInfoMap; + /// ThisAdjustment - A 'this' pointer adjustment thunk. struct ThisAdjustment { /// NonVirtual - The non-virtual adjustment from the derived object to its /// nearest virtual base. int64_t NonVirtual; - /// FIXME: Add VCallOffsetOffset here. + /// VCallOffsetOffset - The offset (in bytes), relative to the address point, + /// of the virtual call offset. + int64_t VCallOffsetOffset; - ThisAdjustment() : NonVirtual(0) { } + ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { } - bool isEmpty() const { return !NonVirtual; } + bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; } }; /// ThisAdjustments - The 'this' pointer adjustments needed in this vtable. llvm::SmallVector<std::pair<uint64_t, ThisAdjustment>, 16> ThisAdjustments; + + /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the + /// part of the vtable we're currently building. + void ComputeThisAdjustments(); typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; - /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the - /// given class. - void AddVCallAndVBaseOffsets(const CXXRecordDecl *RD, int64_t OffsetToTop, - VisitedVirtualBasesSetTy &VBases); - - /// AddVBaseOffsets - Add vbase offsets for the given class. - void AddVBaseOffsets(const CXXRecordDecl *RD, int64_t OffsetToTop, - VisitedVirtualBasesSetTy &VBases); + /// PrimaryVirtualBases - All known virtual bases who are a primary base of + /// some other base. + VisitedVirtualBasesSetTy PrimaryVirtualBases; /// ComputeReturnAdjustment - Compute the return adjustment given a return /// adjustment base offset. - ReturnAdjustment ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset); + ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset); - /// ComputeThisAdjustment - Compute the 'this' pointer adjustment given a - /// 'this' pointer adjustment base offset. - ThisAdjustment ComputeThisAdjustment(FinalOverriders::BaseOffset Offset); + /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting + /// the 'this' pointer from the base subobject to the derived subobject. + BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base, + BaseSubobject Derived) const; + + /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the + /// given virtual member function and the 'this' pointer adjustment base + /// offset. + ThisAdjustment ComputeThisAdjustment(const CXXMethodDecl *MD, + BaseOffset Offset); /// AddMethod - Add a single virtual member function to the vtable /// components vector. - void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment, - ThisAdjustment ThisAdjustment); + void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment); + /// IsOverriderUsed - Returns whether the overrider will ever be used in this + /// part of the vtable. + /// + /// Itanium C++ ABI 2.5.2: + /// + /// struct A { virtual void f(); }; + /// struct B : virtual public A { int i; }; + /// struct C : virtual public A { int j; }; + /// struct D : public B, public C {}; + /// + /// When B and C are declared, A is a primary base in each case, so although + /// vcall offsets are allocated in the A-in-B and A-in-C vtables, no this + /// adjustment is required and no thunk is generated. However, inside D + /// objects, A is no longer a primary base of C, so if we allowed calls to + /// C::f() to use the copy of A's vtable in the C subobject, we would need + /// to adjust this from C* to B::A*, which would require a third-party + /// thunk. Since we require that a call to C::f() first convert to A*, + /// C-in-D's copy of A's vtable is never referenced, so this is not + /// necessary. + bool IsOverriderUsed(BaseSubobject Base, + BaseSubobject FirstBaseInPrimaryBaseChain, + uint64_t OffsetInLayoutClass, + FinalOverriders::OverriderInfo Overrider) const; + /// AddMethods - Add the methods of this base subobject and all its /// primary bases to the vtable components vector. - void AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases); - - /// LayoutVtable - Layout a vtable and all its secondary vtables. - void LayoutVtable(BaseSubobject Base); + void AddMethods(BaseSubobject Base, BaseSubobject FirstBaseInPrimaryBaseChain, + uint64_t OffsetInLayoutClass, + PrimaryBasesSetVectorTy &PrimaryBases); + + // LayoutVtable - Layout the vtable for the given base class, including its + // secondary vtables and any vtables for virtual bases. + void LayoutVtable(); + + /// LayoutPrimaryAndSecondaryVtables - Layout the primary vtable for the + /// given base subobject, as well as all its secondary vtables. + void LayoutPrimaryAndSecondaryVtables(BaseSubobject Base, + bool BaseIsVirtual, + uint64_t OffsetInLayoutClass); + /// LayoutSecondaryVtables - Layout the secondary vtables for the given base + /// subobject. + void LayoutSecondaryVtables(BaseSubobject Base, uint64_t OffsetInLayoutClass); + + /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this + /// class hierarchy. + void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases); + + /// LayoutVtablesForVirtualBases - Layout vtables for all virtual bases of the + /// given base (excluding any primary bases). + void LayoutVtablesForVirtualBases(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases); + + /// isBuildingConstructionVtable - Return whether this vtable builder is + /// building a construction vtable. + bool isBuildingConstructorVtable() const { + return MostDerivedClass != LayoutClass; + } + public: - VtableBuilder(CGVtableInfo &VtableInfo, const CXXRecordDecl *MostDerivedClass) - : VtableInfo(VtableInfo), MostDerivedClass(MostDerivedClass), - Context(MostDerivedClass->getASTContext()), Overriders(MostDerivedClass) { + VtableBuilder(CGVtableInfo &VtableInfo, const CXXRecordDecl *MostDerivedClass, + uint64_t MostDerivedClassOffset, bool MostDerivedClassIsVirtual, + const CXXRecordDecl *LayoutClass) + : VtableInfo(VtableInfo), MostDerivedClass(MostDerivedClass), + MostDerivedClassOffset(MostDerivedClassOffset), + MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), + LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), + Overriders(MostDerivedClass) { - LayoutVtable(BaseSubobject(MostDerivedClass, 0)); + LayoutVtable(); } /// dumpLayout - Dump the vtable layout. void dumpLayout(llvm::raw_ostream&); }; -/// OverridesMethodInPrimaryBase - Checks whether whether this virtual member -/// function overrides a member function in a direct or indirect primary base. +/// OverridesMethodInBases - Checks whether whether this virtual member +/// function overrides a member function in any of the given bases. /// Returns the overridden member function, or null if none was found. static const CXXMethodDecl * -OverridesMethodInPrimaryBase(const CXXMethodDecl *MD, - VtableBuilder::PrimaryBasesSetTy &PrimaryBases) { +OverridesMethodInBases(const CXXMethodDecl *MD, + VtableBuilder::PrimaryBasesSetVectorTy &Bases) { for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I != E; ++I) { const CXXMethodDecl *OverriddenMD = *I; @@ -847,15 +1244,77 @@ OverridesMethodInPrimaryBase(const CXXMethodDecl *MD, assert(OverriddenMD->isCanonicalDecl() && "Should have the canonical decl of the overridden RD!"); - if (PrimaryBases.count(OverriddenRD)) + if (Bases.count(OverriddenRD)) return OverriddenMD; } return 0; } +void VtableBuilder::ComputeThisAdjustments() { + std::map<uint64_t, ThisAdjustment> SortedThisAdjustments; + + // Now go through the method info map and see if any of the methods need + // 'this' pointer adjustments. + for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), + E = MethodInfoMap.end(); I != E; ++I) { + const CXXMethodDecl *MD = I->first; + const MethodInfo &MethodInfo = I->second; + + BaseSubobject OverriddenBaseSubobject(MD->getParent(), + MethodInfo.BaseOffset); + + // Get the final overrider for this method. + FinalOverriders::OverriderInfo Overrider = + Overriders.getOverrider(OverriddenBaseSubobject, MD); + + // Check if we need an adjustment. + if (Overrider.Offset == (int64_t)MethodInfo.BaseOffset) + continue; + + uint64_t VtableIndex = MethodInfo.VtableIndex; + + // Ignore adjustments for pure virtual member functions. + if (Overrider.Method->isPure()) + continue; + + // Ignore adjustments for unused function pointers. + if (Components[VtableIndex].getKind() == + VtableComponent::CK_UnusedFunctionPointer) + continue; + + BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(), + Overrider.Offset); + + // Compute the adjustment offset. + BaseOffset ThisAdjustmentOffset = + ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject, + OverriderBaseSubobject); + + // Then compute the adjustment itself. + ThisAdjustment ThisAdjustment = ComputeThisAdjustment(Overrider.Method, + ThisAdjustmentOffset); + + // Add it. + SortedThisAdjustments.insert(std::make_pair(VtableIndex, ThisAdjustment)); + + if (isa<CXXDestructorDecl>(MD)) { + // Add an adjustment for the deleting destructor as well. + SortedThisAdjustments.insert(std::make_pair(VtableIndex + 1, + ThisAdjustment)); + } + } + + /// Clear the method info map. + MethodInfoMap.clear(); + + // Add the sorted elements. + ThisAdjustments.append(SortedThisAdjustments.begin(), + SortedThisAdjustments.end()); +} + VtableBuilder::ReturnAdjustment -VtableBuilder::ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset) { +VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { ReturnAdjustment Adjustment; if (!Offset.isEmpty()) { @@ -876,79 +1335,96 @@ VtableBuilder::ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset) { return Adjustment; } -VtableBuilder::ThisAdjustment -VtableBuilder::ComputeThisAdjustment(FinalOverriders::BaseOffset Offset) { - ThisAdjustment Adjustment; +BaseOffset +VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, + BaseSubobject Derived) const { + const CXXRecordDecl *BaseRD = Base.getBase(); + const CXXRecordDecl *DerivedRD = Derived.getBase(); - if (!Offset.isEmpty()) { - assert(!Offset.VirtualBase && "FIXME: Handle virtual bases!"); - Adjustment.NonVirtual = Offset.NonVirtualOffset; + CXXBasePaths Paths(/*FindAmbiguities=*/true, + /*RecordPaths=*/true, /*DetectVirtual=*/true); + + if (!const_cast<CXXRecordDecl *>(DerivedRD)-> + isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return BaseOffset(); } - - return Adjustment; -} -void -VtableBuilder::AddVCallAndVBaseOffsets(const CXXRecordDecl *RD, - int64_t OffsetToTop, - VisitedVirtualBasesSetTy &VBases) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + // We have to go through all the paths, and see which one leads us to the + // right base subobject. + for (CXXBasePaths::const_paths_iterator I = Paths.begin(), E = Paths.end(); + I != E; ++I) { + BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, *I); + + // FIXME: Should not use * 8 here. + uint64_t OffsetToBaseSubobject = Offset.NonVirtualOffset * 8; + + if (Offset.VirtualBase) { + // If we have a virtual base class, the non-virtual offset is relative + // to the virtual base class offset. + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + /// Get the virtual base offset, relative to the most derived class + /// layout. + OffsetToBaseSubobject += + MostDerivedClassLayout.getVBaseClassOffset(Offset.VirtualBase); + } else { + // Otherwise, the non-virtual offset is relative to the derived class + // offset. + OffsetToBaseSubobject += Derived.getBaseOffset(); + } + + // Check if this path gives us the right base subobject. + if (OffsetToBaseSubobject == Base.getBaseOffset()) { + // Since we're going from the base class _to_ the derived class, we'll + // invert the non-virtual offset here. + Offset.NonVirtualOffset = -Offset.NonVirtualOffset; + return Offset; + } + } - // Itanium C++ ABI 2.5.2: - // ..in classes sharing a virtual table with a primary base class, the vcall - // and vbase offsets added by the derived class all come before the vcall - // and vbase offsets required by the base class, so that the latter may be - // laid out as required by the base class without regard to additions from - // the derived class(es). - - // (Since we're emitting the vcall and vbase offsets in reverse order, we'll - // emit them for the primary base first). - if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) - AddVCallAndVBaseOffsets(PrimaryBase, OffsetToTop, VBases); - - AddVBaseOffsets(RD, OffsetToTop, VBases); + return BaseOffset(); } + -void VtableBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, - int64_t OffsetToTop, - VisitedVirtualBasesSetTy &VBases) { - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - // Add vbase offsets. - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - - // Check if this is a virtual base that we haven't visited before. - if (I->isVirtual() && VBases.insert(BaseDecl)) { - // FIXME: We shouldn't use / 8 here. - uint64_t Offset = - OffsetToTop + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl) / 8; - - VCallAndVBaseOffsets.push_back(VtableComponent::MakeVBaseOffset(Offset)); +VtableBuilder::ThisAdjustment +VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, + BaseOffset Offset) { + ThisAdjustment Adjustment; + + if (!Offset.isEmpty()) { + if (Offset.VirtualBase) { + // Get the vcall offset map for this virtual base. + VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase]; + + if (VCallOffsets.empty()) { + // We don't have vcall offsets for this virtual base, go ahead and + // build them. + VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass, + /*FinalOverriders=*/0, + BaseSubobject(Offset.VirtualBase, 0), + /*BaseIsVirtual=*/true, + /*OffsetInLayoutClass=*/0); + + VCallOffsets = Builder.getVCallOffsets(); + } + + Adjustment.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD); } - - // Check the base class looking for more vbase offsets. - AddVBaseOffsets(BaseDecl, OffsetToTop, VBases); + + Adjustment.NonVirtual = Offset.NonVirtualOffset; } + + return Adjustment; } void VtableBuilder::AddMethod(const CXXMethodDecl *MD, - ReturnAdjustment ReturnAdjustment, - ThisAdjustment ThisAdjustment) { + ReturnAdjustment ReturnAdjustment) { if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { assert(ReturnAdjustment.isEmpty() && "Destructor can't have return adjustment!"); - // Add the 'this' pointer adjustments if necessary. - if (!ThisAdjustment.isEmpty()) { - ThisAdjustments.push_back(std::make_pair(Components.size(), - ThisAdjustment)); - ThisAdjustments.push_back(std::make_pair(Components.size() + 1, - ThisAdjustment)); - } // Add both the complete destructor and the deleting destructor. Components.push_back(VtableComponent::MakeCompleteDtor(DD)); @@ -959,30 +1435,157 @@ VtableBuilder::AddMethod(const CXXMethodDecl *MD, ReturnAdjustments.push_back(std::make_pair(Components.size(), ReturnAdjustment)); - // Add the 'this' pointer adjustment if necessary. - if (!ThisAdjustment.isEmpty()) - ThisAdjustments.push_back(std::make_pair(Components.size(), - ThisAdjustment)); - // Add the function. Components.push_back(VtableComponent::MakeFunction(MD)); } } +/// OverridesIndirectMethodInBase - Return whether the given member function +/// overrides any methods in the set of given bases. +/// Unlike OverridesMethodInBase, this checks "overriders of overriders". +/// For example, if we have: +/// +/// struct A { virtual void f(); } +/// struct B : A { virtual void f(); } +/// struct C : B { virtual void f(); } +/// +/// OverridesIndirectMethodInBase will return true if given C::f as the method +/// and { A } as the set of bases. +static bool +OverridesIndirectMethodInBases(const CXXMethodDecl *MD, + VtableBuilder::PrimaryBasesSetVectorTy &Bases) { + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); + assert(OverriddenMD->isCanonicalDecl() && + "Should have the canonical decl of the overridden RD!"); + + if (Bases.count(OverriddenRD)) + return true; + + // Check "indirect overriders". + if (OverridesIndirectMethodInBases(OverriddenMD, Bases)) + return true; + } + + return false; +} + +bool +VtableBuilder::IsOverriderUsed(BaseSubobject Base, + BaseSubobject FirstBaseInPrimaryBaseChain, + uint64_t OffsetInLayoutClass, + FinalOverriders::OverriderInfo Overrider) const { + // If the base and the first base in the primary base chain have the same + // offsets, then this overrider will be used. + if (Base.getBaseOffset() == OffsetInLayoutClass) + return true; + + // We know now that Base (or a direct or indirect base of it) is a primary + // base in part of the class hierarchy, but not a primary base in the most + // derived class. + + // If the overrider is the first base in the primary base chain, we know + // that the overrider will be used. + if (Overrider.Method->getParent() == FirstBaseInPrimaryBaseChain.getBase()) + return true; + + VtableBuilder::PrimaryBasesSetVectorTy PrimaryBases; + + const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain.getBase(); + PrimaryBases.insert(RD); + + // Now traverse the base chain, starting with the first base, until we find + // the base that is no longer a primary base. + while (true) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + if (!PrimaryBase) + break; + + if (Layout.getPrimaryBaseWasVirtual()) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary base should always be at offset 0!"); + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + + // Now check if this is the primary base that is not a primary base in the + // most derived class. + if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != + OffsetInLayoutClass) { + // We found it, stop walking the chain. + break; + } + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should always be at offset 0!"); + } + + if (!PrimaryBases.insert(PrimaryBase)) + assert(false && "Found a duplicate primary base!"); + + RD = PrimaryBase; + } + + // If the final overrider is an override of one of the primary bases, + // then we know that it will be used. + return OverridesIndirectMethodInBases(Overrider.Method, PrimaryBases); +} + +/// FindNearestOverriddenMethod - Given a method, returns the overridden method +/// from the nearest base. Returns null if no method was found. +static const CXXMethodDecl * +FindNearestOverriddenMethod(const CXXMethodDecl *MD, + VtableBuilder::PrimaryBasesSetVectorTy &Bases) { + for (int I = Bases.size(), E = 0; I != E; --I) { + const CXXRecordDecl *PrimaryBase = Bases[I - 1]; + + // Now check the overriden methods. + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + + // We found our overridden method. + if (OverriddenMD->getParent() == PrimaryBase) + return OverriddenMD; + } + } + + return 0; +} + void -VtableBuilder::AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases) { +VtableBuilder::AddMethods(BaseSubobject Base, + BaseSubobject FirstBaseInPrimaryBaseChain, + uint64_t OffsetInLayoutClass, + PrimaryBasesSetVectorTy &PrimaryBases) { const CXXRecordDecl *RD = Base.getBase(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - if (Layout.getPrimaryBaseWasVirtual()) - assert(false && "FIXME: Handle vbases here."); - else + uint64_t BaseOffset; + if (Layout.getPrimaryBaseWasVirtual()) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + } else { assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && "Primary base should have a zero offset!"); - - AddMethods(BaseSubobject(PrimaryBase, Base.getBaseOffset()), PrimaryBases); + + BaseOffset = Base.getBaseOffset(); + } + + // FIXME: OffsetInLayoutClass is not right here. + AddMethods(BaseSubobject(PrimaryBase, BaseOffset), + FirstBaseInPrimaryBaseChain, OffsetInLayoutClass, PrimaryBases); if (!PrimaryBases.insert(PrimaryBase)) assert(false && "Found a duplicate primary base!"); @@ -1004,47 +1607,90 @@ VtableBuilder::AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases) { // base. If this is the case, and the return type doesn't require adjustment // then we can just use the member function from the primary base. if (const CXXMethodDecl *OverriddenMD = - OverridesMethodInPrimaryBase(MD, PrimaryBases)) { + FindNearestOverriddenMethod(MD, PrimaryBases)) { if (ComputeReturnAdjustmentBaseOffset(Context, MD, - OverriddenMD).isEmpty()) + OverriddenMD).isEmpty()) { + // Replace the method info of the overridden method with our own + // method. + assert(MethodInfoMap.count(OverriddenMD) && + "Did not find the overridden method!"); + MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD]; + + MethodInfo MethodInfo(Base.getBaseOffset(), + OverriddenMethodInfo.VtableIndex); + + assert(!MethodInfoMap.count(MD) && + "Should not have method info for this method yet!"); + + MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); + MethodInfoMap.erase(OverriddenMD); continue; + } } + // Insert the method info for this method. + MethodInfo MethodInfo(Base.getBaseOffset(), Components.size()); + + assert(!MethodInfoMap.count(MD) && + "Should not have method info for this method yet!"); + MethodInfoMap.insert(std::make_pair(MD, MethodInfo)); + + // Check if this overrider is going to be used. + if (!IsOverriderUsed(Base, FirstBaseInPrimaryBaseChain, OffsetInLayoutClass, + Overrider)) { + const CXXMethodDecl *OverriderMD = Overrider.Method; + Components.push_back(VtableComponent::MakeUnusedFunction(OverriderMD)); + continue; + } + // Check if this overrider needs a return adjustment. - FinalOverriders::BaseOffset ReturnAdjustmentOffset = + BaseOffset ReturnAdjustmentOffset = Overriders.getReturnAdjustmentOffset(Base, MD); ReturnAdjustment ReturnAdjustment = ComputeReturnAdjustment(ReturnAdjustmentOffset); - // Check if this overrider needs a 'this' pointer adjustment. - FinalOverriders::BaseOffset ThisAdjustmentOffset = - Overriders.getThisAdjustmentOffset(Base, MD); - - ThisAdjustment ThisAdjustment = ComputeThisAdjustment(ThisAdjustmentOffset); - - AddMethod(Overrider.Method, ReturnAdjustment, ThisAdjustment); + AddMethod(Overrider.Method, ReturnAdjustment); } } -void VtableBuilder::LayoutVtable(BaseSubobject Base) { - const CXXRecordDecl *RD = Base.getBase(); - assert(RD->isDynamicClass() && "class does not have a vtable!"); - - int64_t OffsetToTop = -(int64_t)Base.getBaseOffset() / 8; - - // Add vcall and vbase offsets for this vtable. +void VtableBuilder::LayoutVtable() { + LayoutPrimaryAndSecondaryVtables(BaseSubobject(MostDerivedClass, 0), + MostDerivedClassIsVirtual, + MostDerivedClassOffset); + VisitedVirtualBasesSetTy VBases; - AddVCallAndVBaseOffsets(RD, OffsetToTop, VBases); + + // Determine the primary virtual bases. + DeterminePrimaryVirtualBases(MostDerivedClass, VBases); + VBases.clear(); + + LayoutVtablesForVirtualBases(MostDerivedClass, VBases); +} + +void +VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base, + bool BaseIsVirtual, + uint64_t OffsetInLayoutClass) { + assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); - // Reverse them and add them to the vtable components. - std::reverse(VCallAndVBaseOffsets.begin(), VCallAndVBaseOffsets.end()); - Components.append(VCallAndVBaseOffsets.begin(), VCallAndVBaseOffsets.end()); - VCallAndVBaseOffsets.clear(); + // Add vcall and vbase offsets for this vtable. + VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders, + Base, BaseIsVirtual, OffsetInLayoutClass); + Components.append(Builder.components_begin(), Builder.components_end()); + // Check if we need to add these vcall offsets. + if (BaseIsVirtual && !Builder.getVCallOffsets().empty()) { + VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()]; + + if (VCallOffsets.empty()) + VCallOffsets = Builder.getVCallOffsets(); + } + // Add the offset to top. - // FIXME: This is not going to be right for construction vtables. // FIXME: We should not use / 8 here. + int64_t OffsetToTop = -(int64_t)(OffsetInLayoutClass - + MostDerivedClassOffset) / 8; Components.push_back(VtableComponent::MakeOffsetToTop(OffsetToTop)); // Next, add the RTTI. @@ -1053,59 +1699,166 @@ void VtableBuilder::LayoutVtable(BaseSubobject Base) { uint64_t AddressPoint = Components.size(); // Now go through all virtual member functions and add them. - PrimaryBasesSetTy PrimaryBases; - AddMethods(Base, PrimaryBases); + PrimaryBasesSetVectorTy PrimaryBases; + AddMethods(Base, Base, OffsetInLayoutClass, PrimaryBases); + + // Compute 'this' pointer adjustments. + ComputeThisAdjustments(); // Record the address point. - AddressPoints.insert(std::make_pair(Base, AddressPoint)); + AddressPoints.insert(std::make_pair(BaseSubobject(Base.getBase(), + OffsetInLayoutClass), + AddressPoint)); // Record the address points for all primary bases. - for (PrimaryBasesSetTy::const_iterator I = PrimaryBases.begin(), + for (PrimaryBasesSetVectorTy::const_iterator I = PrimaryBases.begin(), E = PrimaryBases.end(); I != E; ++I) { const CXXRecordDecl *BaseDecl = *I; // We know that all the primary bases have the same offset as the base // subobject. - BaseSubobject PrimaryBase(BaseDecl, Base.getBaseOffset()); + BaseSubobject PrimaryBase(BaseDecl, OffsetInLayoutClass); AddressPoints.insert(std::make_pair(PrimaryBase, AddressPoint)); } + // Layout secondary vtables. + LayoutSecondaryVtables(Base, OffsetInLayoutClass); +} + +void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base, + uint64_t OffsetInLayoutClass) { + // Itanium C++ ABI 2.5.2: + // Following the primary virtual table of a derived class are secondary + // virtual tables for each of its proper base classes, except any primary + // base(s) with which it shares its primary virtual table. + + const CXXRecordDecl *RD = Base.getBase(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - // Layout secondary vtables. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { + // Ignore virtual bases, we'll emit them later. + if (I->isVirtual()) + continue; + const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); // Ignore bases that don't have a vtable. if (!BaseDecl->isDynamicClass()) continue; + + // Get the base offset of this base. + uint64_t RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl); + uint64_t BaseOffset = Base.getBaseOffset() + RelativeBaseOffset; - // Ignore the primary base. - if (BaseDecl == PrimaryBase) + uint64_t BaseOffsetInLayoutClass = OffsetInLayoutClass + RelativeBaseOffset; + + // Don't emit a secondary vtable for a primary base. We might however want + // to emit secondary vtables for other bases of this base. + if (BaseDecl == PrimaryBase) { + LayoutSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset), + BaseOffsetInLayoutClass); continue; + } - // Ignore virtual bases, we'll emit them later. - if (I->isVirtual()) + // Layout the primary vtable (and any secondary vtables) for this base. + LayoutPrimaryAndSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset), + /*BaseIsVirtual=*/false, + BaseOffsetInLayoutClass); + } +} + +void +VtableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // Check if this base has a primary base. + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + + // Check if it's virtual. + if (Layout.getPrimaryBaseWasVirtual()) { + bool IsPrimaryVirtualBase = true; + + if (isBuildingConstructorVtable()) { + // Check if the base is actually a primary base in the class we use for + // layout. + // FIXME: Is this check enough? + if (MostDerivedClassOffset != 0) + IsPrimaryVirtualBase = false; + } + + if (IsPrimaryVirtualBase) + PrimaryVirtualBases.insert(PrimaryBase); + } + } + + // Traverse bases, looking for more primary virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + if (I->isVirtual() && !VBases.insert(BaseDecl)) continue; - - // Get the base offset of this base. - uint64_t BaseOffset = Base.getBaseOffset() + - Layout.getBaseClassOffset(BaseDecl); - // Layout this secondary vtable. - LayoutVtable(BaseSubobject(BaseDecl, BaseOffset)); + DeterminePrimaryVirtualBases(BaseDecl, VBases); + } +} + +void +VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases) { + // Itanium C++ ABI 2.5.2: + // Then come the virtual base virtual tables, also in inheritance graph + // order, and again excluding primary bases (which share virtual tables with + // the classes for which they are primary). + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Check if this base needs a vtable. (If it's virtual, not a primary base + // of some other class, and we haven't visited it before). + if (I->isVirtual() && BaseDecl->isDynamicClass() && + !PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) { + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + uint64_t BaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); + uint64_t BaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(BaseDecl); + + LayoutPrimaryAndSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset), + /*BaseIsVirtual=*/true, + BaseOffsetInLayoutClass); + } + + // We only need to check the base for virtual base vtables if it actually + // has virtual bases. + if (BaseDecl->getNumVBases()) + LayoutVtablesForVirtualBases(BaseDecl, VBases); } - - // FIXME: Emit vtables for virtual bases here. } /// dumpLayout - Dump the vtable layout. void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { - - Out << "Vtable for '" << MostDerivedClass->getQualifiedNameAsString(); + + if (MostDerivedClass == LayoutClass) { + Out << "Vtable for '"; + Out << MostDerivedClass->getQualifiedNameAsString(); + } else { + Out << "Construction vtable for ('"; + Out << MostDerivedClass->getQualifiedNameAsString() << "', "; + // FIXME: Don't use / 8 . + Out << MostDerivedClassOffset / 8 << ") in '"; + Out << LayoutClass->getQualifiedNameAsString(); + } Out << "' (" << Components.size() << " entries).\n"; // Iterate through the address points and insert them into a new map where @@ -1125,37 +1878,6 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { unsigned NextThisAdjustmentIndex = 0; for (unsigned I = 0, E = Components.size(); I != E; ++I) { uint64_t Index = I; - - if (AddressPointsByIndex.count(I)) { - if (AddressPointsByIndex.count(Index) == 1) { - const BaseSubobject &Base = AddressPointsByIndex.find(Index)->second; - - // FIXME: Instead of dividing by 8, we should be using CharUnits. - Out << " -- (" << Base.getBase()->getQualifiedNameAsString(); - Out << ", " << Base.getBaseOffset() / 8 << ") vtable address --\n"; - } else { - uint64_t BaseOffset = - AddressPointsByIndex.lower_bound(Index)->second.getBaseOffset(); - - // We store the class names in a set to get a stable order. - std::set<std::string> ClassNames; - for (std::multimap<uint64_t, BaseSubobject>::const_iterator I = - AddressPointsByIndex.lower_bound(Index), E = - AddressPointsByIndex.upper_bound(Index); I != E; ++I) { - assert(I->second.getBaseOffset() == BaseOffset && - "Invalid base offset!"); - const CXXRecordDecl *RD = I->second.getBase(); - ClassNames.insert(RD->getQualifiedNameAsString()); - } - - for (std::set<std::string>::const_iterator I = ClassNames.begin(), - E = ClassNames.end(); I != E; ++I) { - // FIXME: Instead of dividing by 8, we should be using CharUnits. - Out << " -- (" << *I; - Out << ", " << BaseOffset / 8 << ") vtable address --\n"; - } - } - } Out << llvm::format("%4d | ", I); @@ -1163,9 +1885,9 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { // Dump the component. switch (Component.getKind()) { - // FIXME: Remove this default case. - default: - assert(false && "Unhandled component kind!"); + + case VtableComponent::CK_VCallOffset: + Out << "vcall_offset (" << Component.getVCallOffset() << ")"; break; case VtableComponent::CK_VBaseOffset: @@ -1201,6 +1923,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { if (Adjustment.VBaseOffsetOffset) Out << ", " << Adjustment.VBaseOffsetOffset << " vbase offset offset"; + Out << ']'; NextReturnAdjustmentIndex++; @@ -1214,7 +1937,10 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { Out << "\n [this adjustment: "; Out << Adjustment.NonVirtual << " non-virtual"; - + + if (Adjustment.VCallOffsetOffset) + Out << ", " << Adjustment.VCallOffsetOffset << " vcall offset offset"; + Out << ']'; NextThisAdjustmentIndex++; @@ -1223,31 +1949,94 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { break; } - case VtableComponent::CK_CompleteDtorPointer: { + case VtableComponent::CK_CompleteDtorPointer: + case VtableComponent::CK_DeletingDtorPointer: { + bool IsComplete = + Component.getKind() == VtableComponent::CK_CompleteDtorPointer; + const CXXDestructorDecl *DD = Component.getDestructorDecl(); - Out << DD->getQualifiedNameAsString() << "() [complete]"; + Out << DD->getQualifiedNameAsString(); + if (IsComplete) + Out << "() [complete]"; + else + Out << "() [deleting]"; + if (DD->isPure()) Out << " [pure]"; + // If this destructor has a 'this' pointer adjustment, dump it. + if (NextThisAdjustmentIndex < ThisAdjustments.size() && + ThisAdjustments[NextThisAdjustmentIndex].first == I) { + const ThisAdjustment Adjustment = + ThisAdjustments[NextThisAdjustmentIndex].second; + + Out << "\n [this adjustment: "; + Out << Adjustment.NonVirtual << " non-virtual"; + + if (Adjustment.VCallOffsetOffset) + Out << ", " << Adjustment.VCallOffsetOffset << " vcall offset offset"; + + Out << ']'; + + NextThisAdjustmentIndex++; + } + + break; } - case VtableComponent::CK_DeletingDtorPointer: { - const CXXDestructorDecl *DD = Component.getDestructorDecl(); - - Out << DD->getQualifiedNameAsString() << "() [deleting]"; - if (DD->isPure()) - Out << " [pure]"; + case VtableComponent::CK_UnusedFunctionPointer: { + const CXXMethodDecl *MD = Component.getUnusedFunctionDecl(); - break; + std::string Str = + PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, + MD); + Out << "[unused] " << Str; + if (MD->isPure()) + Out << " [pure]"; } } Out << '\n'; + + // Dump the next address point. + uint64_t NextIndex = Index + 1; + if (AddressPointsByIndex.count(NextIndex)) { + if (AddressPointsByIndex.count(NextIndex) == 1) { + const BaseSubobject &Base = + AddressPointsByIndex.find(NextIndex)->second; + + // FIXME: Instead of dividing by 8, we should be using CharUnits. + Out << " -- (" << Base.getBase()->getQualifiedNameAsString(); + Out << ", " << Base.getBaseOffset() / 8 << ") vtable address --\n"; + } else { + uint64_t BaseOffset = + AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset(); + + // We store the class names in a set to get a stable order. + std::set<std::string> ClassNames; + for (std::multimap<uint64_t, BaseSubobject>::const_iterator I = + AddressPointsByIndex.lower_bound(NextIndex), E = + AddressPointsByIndex.upper_bound(NextIndex); I != E; ++I) { + assert(I->second.getBaseOffset() == BaseOffset && + "Invalid base offset!"); + const CXXRecordDecl *RD = I->second.getBase(); + ClassNames.insert(RD->getQualifiedNameAsString()); + } + + for (std::set<std::string>::const_iterator I = ClassNames.begin(), + E = ClassNames.end(); I != E; ++I) { + // FIXME: Instead of dividing by 8, we should be using CharUnits. + Out << " -- (" << *I; + Out << ", " << BaseOffset / 8 << ") vtable address --\n"; + } + } + } } - + + Out << '\n'; } } @@ -1500,10 +2289,10 @@ private: // If already set, note the two sets as the same if (0) printf("%s::%s same as %s::%s\n", - PrevU->getParent()->getNameAsCString(), - PrevU->getNameAsCString(), - U->getParent()->getNameAsCString(), - U->getNameAsCString()); + PrevU->getParent()->getNameAsString().c_str(), + PrevU->getNameAsString().c_str(), + U->getParent()->getNameAsString().c_str(), + U->getNameAsString().c_str()); ForwardUnique[PrevU] = U; return; } @@ -1511,11 +2300,11 @@ private: // Not set, set it now if (0) printf("marking %s::%s %p override as %s::%s\n", - MD->getParent()->getNameAsCString(), - MD->getNameAsCString(), + MD->getParent()->getNameAsString().c_str(), + MD->getNameAsString().c_str(), (void*)MD, - U->getParent()->getNameAsCString(), - U->getNameAsCString()); + U->getParent()->getNameAsString().c_str(), + U->getNameAsString().c_str()); UniqueOverrider[MD] = U; for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(), @@ -1537,8 +2326,8 @@ private: BuildUniqueOverrider(MD, MD); if (0) printf("top set is %s::%s %p\n", - MD->getParent()->getNameAsCString(), - MD->getNameAsCString(), + MD->getParent()->getNameAsString().c_str(), + MD->getNameAsString().c_str(), (void*)MD); ForwardUnique[MD] = MD; } @@ -1573,7 +2362,7 @@ private: A_t::iterator J = I; while (++J != E && DclCmp(I, J) == 0) if (DclIsSame(*I, *J)) { - if (0) printf("connecting %s\n", (*I)->getNameAsCString()); + if (0) printf("connecting %s\n", (*I)->getNameAsString().c_str()); ForwardUnique[*J] = *I; } } @@ -1657,7 +2446,7 @@ public: } //#define D1(x) -#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0) +#define D1(X) do { if (getenv("CLANG_VTABLE_DEBUG")) { X; } } while (0) void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, bool updateVBIndex, Index_t current_vbindex) { @@ -1801,7 +2590,7 @@ public: return; D1(printf(" vfn for %s at %d\n", - dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsCString(), + dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsString().c_str(), (int)Methods.size())); // We didn't find an entry in the vtable that we could use, add a new @@ -1824,7 +2613,7 @@ public: idx = VCalls.size()+1; VCalls.push_back(Offset/8 - CurrentVBaseOffset/8); D1(printf(" vcall for %s at %d with delta %d\n", - dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsCString(), + dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsString().c_str(), (int)-VCalls.size()-3, (int)VCalls[idx-1])); } } @@ -2352,7 +3141,7 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // Collect all the primary bases, so we can check whether methods override // a method from the base. - VtableBuilder::PrimaryBasesSetTy PrimaryBases; + VtableBuilder::PrimaryBasesSetVectorTy PrimaryBases; for (ASTRecordLayout::primary_base_info_iterator I = Layout.primary_base_begin(), E = Layout.primary_base_end(); I != E; ++I) @@ -2370,7 +3159,7 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // Check if this method overrides a method in the primary base. if (const CXXMethodDecl *OverriddenMD = - OverridesMethodInPrimaryBase(MD, PrimaryBases)) { + OverridesMethodInBases(MD, PrimaryBases)) { // Check if converting from the return type of the method to the // return type of the overridden method requires conversion. if (ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD, @@ -2535,12 +3324,25 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, bool GenerateDefinition, const CXXRecordDecl *LayoutClass, const CXXRecordDecl *RD, uint64_t Offset, + bool IsVirtual, AddressPointsMapTy& AddressPoints) { - if (GenerateDefinition && CGM.getLangOptions().DumpVtableLayouts && - LayoutClass == RD) { - VtableBuilder Builder(*this, RD); - - Builder.dumpLayout(llvm::errs()); + if (GenerateDefinition) { + if (LayoutClass == RD) { + assert(!IsVirtual && + "Can't only have a virtual base in construction vtables!"); + VtableBuilder Builder(*this, RD, Offset, + /*MostDerivedClassIsVirtual=*/false, + LayoutClass); + + if (CGM.getLangOptions().DumpVtableLayouts) + Builder.dumpLayout(llvm::errs()); + } else if (CGM.getLangOptions().DumpVtableLayouts) { + // We only build construction vtables when dumping vtable layouts for now. + VtableBuilder Builder(*this, RD, Offset, + /*MostDerivedClassIsVirtual=*/IsVirtual, + LayoutClass); + Builder.dumpLayout(llvm::errs()); + } } llvm::SmallString<256> OutName; @@ -2601,6 +3403,7 @@ void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, AddressPointsMapTy AddressPoints; Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0, + /*IsVirtual=*/false, AddressPoints); GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD); } @@ -2612,7 +3415,7 @@ llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { AddressPointsMapTy AddressPoints; Vtable = GenerateVtable(llvm::GlobalValue::ExternalLinkage, /*GenerateDefinition=*/false, RD, RD, 0, - AddressPoints); + /*IsVirtual=*/false, AddressPoints); } return Vtable; diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index 471d638..6ccb011 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -185,7 +185,7 @@ private: llvm::GlobalVariable * GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, bool GenerateDefinition, const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, uint64_t Offset, + const CXXRecordDecl *RD, uint64_t Offset, bool IsVirtual, AddressPointsMapTy& AddressPoints); llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, @@ -239,7 +239,8 @@ public: }; CtorVtableInfo getCtorVtable(const CXXRecordDecl *RD, - const BaseSubobject &Base); + const BaseSubobject &Base, + bool BaseIsVirtual); llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 5a4f94e..f455827 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -30,7 +30,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) Builder(cgm.getModule().getContext()), DebugInfo(0), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0), - CXXThisDecl(0), CXXVTTDecl(0), + CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0), ConditionalBranchLevel(0), TerminateHandler(0), TrapBB(0), UniqueAggrDestructorCount(0) { LLVMIntTy = ConvertType(getContext().IntTy); @@ -197,7 +197,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, Builder.SetInsertPoint(EntryBB); - QualType FnType = getContext().getFunctionType(RetTy, 0, 0, false, 0); + QualType FnType = getContext().getFunctionType(RetTy, 0, 0, false, 0, + false, false, 0, 0, + /*FIXME?*/false, + /*FIXME?*/CC_Default); // Emit subprogram debug descriptor. if (CGDebugInfo *DI = getDebugInfo()) { @@ -216,15 +219,20 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, } else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect && hasAggregateLLVMType(CurFnInfo->getReturnType())) { // Indirect aggregate return; emit returned value directly into sret slot. - // This reduces code size, and is also affects correctness in C++. + // This reduces code size, and affects correctness in C++. ReturnValue = CurFn->arg_begin(); } else { - ReturnValue = CreateTempAlloca(ConvertType(RetTy), "retval"); + ReturnValue = CreateIRTemp(RetTy, "retval"); } EmitStartEHSpec(CurCodeDecl); EmitFunctionProlog(*CurFnInfo, CurFn, Args); + if (CXXThisDecl) + CXXThisValue = Builder.CreateLoad(LocalDeclMap[CXXThisDecl], "this"); + if (CXXVTTDecl) + CXXVTTValue = Builder.CreateLoad(LocalDeclMap[CXXVTTDecl], "vtt"); + // If any of the arguments have a variably modified type, make sure to // emit the type size. for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); @@ -236,6 +244,19 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, } } +void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) { + const FunctionDecl *FD = cast<FunctionDecl>(CurGD.getDecl()); + + Stmt *Body = FD->getBody(); + if (Body) + EmitStmt(Body); + else { + assert(FD->isImplicit() && "non-implicit function def has no body"); + assert(FD->isCopyAssignment() && "implicit function not copy assignment"); + SynthesizeCXXCopyAssignment(Args); + } +} + void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); @@ -246,13 +267,13 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { FunctionArgList Args; CurGD = GD; - OuterTryBlock = 0; if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { if (MD->isInstance()) { // Create the implicit 'this' decl. // FIXME: I'm not entirely sure I like using a fake decl just for code // generation. Maybe we can come up with a better way? - CXXThisDecl = ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), + CXXThisDecl = ImplicitParamDecl::Create(getContext(), 0, + FD->getLocation(), &getContext().Idents.get("this"), MD->getThisType(getContext())); Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType())); @@ -262,7 +283,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { // FIXME: The comment about using a fake decl above applies here too. QualType T = getContext().getPointerType(getContext().VoidPtrTy); CXXVTTDecl = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), + ImplicitParamDecl::Create(getContext(), 0, FD->getLocation(), &getContext().Idents.get("vtt"), T); Args.push_back(std::make_pair(CXXVTTDecl, CXXVTTDecl->getType())); } @@ -278,80 +299,22 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { FProto->getArgType(i))); } - if (const CompoundStmt *S = FD->getCompoundBody()) { - StartFunction(GD, FD->getResultType(), Fn, Args, S->getLBracLoc()); - - if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { - EmitCtorPrologue(CD, GD.getCtorType()); - EmitStmt(S); - - // If any of the member initializers are temporaries bound to references - // make sure to emit their destructors. - EmitCleanupBlocks(0); - - } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) { - llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); - PushCleanupBlock(DtorEpilogue); + SourceRange BodyRange; + if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange(); - InitializeVtablePtrs(DD->getParent()); + // Emit the standard function prologue. + StartFunction(GD, FD->getResultType(), Fn, Args, BodyRange.getBegin()); - EmitStmt(S); - - CleanupBlockInfo Info = PopCleanupBlock(); + // Generate the body of the function. + if (isa<CXXDestructorDecl>(FD)) + EmitDestructorBody(Args); + else if (isa<CXXConstructorDecl>(FD)) + EmitConstructorBody(Args); + else + EmitFunctionBody(Args); - assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!"); - EmitBlock(DtorEpilogue); - EmitDtorEpilogue(DD, GD.getDtorType()); - - if (Info.SwitchBlock) - EmitBlock(Info.SwitchBlock); - if (Info.EndBlock) - EmitBlock(Info.EndBlock); - } else { - // Just a regular function, emit its body. - EmitStmt(S); - } - - FinishFunction(S->getRBracLoc()); - } else if (FD->isImplicit()) { - const CXXRecordDecl *ClassDecl = - cast<CXXRecordDecl>(FD->getDeclContext()); - (void) ClassDecl; - if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { - // FIXME: For C++0x, we want to look for implicit *definitions* of - // these special member functions, rather than implicit *declarations*. - if (CD->isCopyConstructor()) { - assert(!ClassDecl->hasUserDeclaredCopyConstructor() && - "Cannot synthesize a non-implicit copy constructor"); - SynthesizeCXXCopyConstructor(CD, GD.getCtorType(), Fn, Args); - } else if (CD->isDefaultConstructor()) { - assert(!ClassDecl->hasUserDeclaredConstructor() && - "Cannot synthesize a non-implicit default constructor."); - SynthesizeDefaultConstructor(CD, GD.getCtorType(), Fn, Args); - } else { - assert(false && "Implicit constructor cannot be synthesized"); - } - } else if (const CXXDestructorDecl *CD = dyn_cast<CXXDestructorDecl>(FD)) { - assert(!ClassDecl->hasUserDeclaredDestructor() && - "Cannot synthesize a non-implicit destructor"); - SynthesizeDefaultDestructor(CD, GD.getDtorType(), Fn, Args); - } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { - assert(MD->isCopyAssignment() && - !ClassDecl->hasUserDeclaredCopyAssignment() && - "Cannot synthesize a method that is not an implicit-defined " - "copy constructor"); - SynthesizeCXXCopyAssignment(MD, Fn, Args); - } else { - assert(false && "Cannot synthesize unknown implicit function"); - } - } else if (const Stmt *S = FD->getBody()) { - if (const CXXTryStmt *TS = dyn_cast<CXXTryStmt>(S)) { - OuterTryBlock = TS; - StartFunction(GD, FD->getResultType(), Fn, Args, TS->getTryLoc()); - EmitStmt(TS); - FinishFunction(TS->getEndLoc()); - } - } + // Emit the standard function epilogue. + FinishFunction(BodyRange.getEnd()); // Destroy the 'this' declaration. if (CXXThisDecl) diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index fb2e5fe..d582c0d 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -55,6 +55,7 @@ namespace clang { class ObjCImplementationDecl; class ObjCPropertyImplDecl; class TargetInfo; + class TargetCodeGenInfo; class VarDecl; class ObjCForCollectionStmt; class ObjCAtTryStmt; @@ -62,7 +63,6 @@ namespace clang { class ObjCAtSynchronizedStmt; namespace CodeGen { - class CodeGenModule; class CodeGenTypes; class CGDebugInfo; class CGFunctionInfo; @@ -91,9 +91,6 @@ public: /// CurGD - The GlobalDecl for the current function being compiled. GlobalDecl CurGD; - /// OuterTryBlock - This is the address of the outter most try block, 0 - /// otherwise. - const Stmt *OuterTryBlock; /// ReturnBlock - Unified return block. llvm::BasicBlock *ReturnBlock; @@ -382,11 +379,13 @@ private: /// CXXThisDecl - When generating code for a C++ member function, /// this will hold the implicit 'this' declaration. ImplicitParamDecl *CXXThisDecl; + llvm::Value *CXXThisValue; /// CXXVTTDecl - When generating code for a base object constructor or /// base object destructor with virtual bases, this will hold the implicit /// VTT parameter. ImplicitParamDecl *CXXVTTDecl; + llvm::Value *CXXVTTValue; /// CXXLiveTemporaryInfo - Holds information about a live C++ temporary. struct CXXLiveTemporaryInfo { @@ -466,7 +465,8 @@ public: //===--------------------------------------------------------------------===// llvm::Value *BuildBlockLiteralTmp(const BlockExpr *); - llvm::Constant *BuildDescriptorBlockDecl(bool BlockHasCopyDispose, + llvm::Constant *BuildDescriptorBlockDecl(const BlockExpr *, + bool BlockHasCopyDispose, CharUnits Size, const llvm::StructType *, std::vector<HelperInfo> *); @@ -492,6 +492,10 @@ public: const FunctionArgList &Args, SourceLocation StartLoc); + void EmitConstructorBody(FunctionArgList &Args); + void EmitDestructorBody(FunctionArgList &Args); + void EmitFunctionBody(FunctionArgList &Args); + /// EmitReturnBlock - Emit the unified return block, trying to avoid its /// emission when possible. void EmitReturnBlock(); @@ -525,24 +529,8 @@ public: llvm::Value *ThisPtr, uint64_t Offset); - void SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, - CXXCtorType Type, - llvm::Function *Fn, - const FunctionArgList &Args); - - void SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, - llvm::Function *Fn, - const FunctionArgList &Args); - - void SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor, - CXXCtorType Type, - llvm::Function *Fn, - const FunctionArgList &Args); - - void SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, - CXXDtorType Type, - llvm::Function *Fn, - const FunctionArgList &Args); + void SynthesizeCXXCopyConstructor(const FunctionArgList &Args); + void SynthesizeCXXCopyAssignment(const FunctionArgList &Args); /// EmitDtorEpilogue - Emit all code that comes at the end of class's /// destructor. This is to call destructors on members and base classes in @@ -663,6 +651,13 @@ public: llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty, const llvm::Twine &Name = "tmp"); + /// CreateIRTemp - Create a temporary IR object of the given type, with + /// appropriate alignment. This routine should only be used when an temporary + /// value needs to be stored into an alloca (for example, to avoid explicit + /// PHI construction), but the type is the IR type, not the type appropriate + /// for storing in memory. + llvm::Value *CreateIRTemp(QualType T, const llvm::Twine &Name = "tmp"); + /// CreateMemTemp - Create a temporary memory object of the given type, with /// appropriate alignment. llvm::Value *CreateMemTemp(QualType T, const llvm::Twine &Name = "tmp"); @@ -738,11 +733,17 @@ public: /// LoadCXXThis - Load the value of 'this'. This function is only valid while /// generating code for an C++ member function. - llvm::Value *LoadCXXThis(); + llvm::Value *LoadCXXThis() { + assert(CXXThisValue && "no 'this' value for this function"); + return CXXThisValue; + } /// LoadCXXVTT - Load the VTT parameter to base constructors/destructors have /// virtual bases. - llvm::Value *LoadCXXVTT(); + llvm::Value *LoadCXXVTT() { + assert(CXXVTTValue && "no VTT value for this function"); + return CXXVTTValue; + } /// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a /// complete class down to one of its virtual bases. @@ -789,6 +790,9 @@ public: const CXXRecordDecl *BaseClassDecl, QualType Ty); + void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, + CXXCtorType CtorType, + const FunctionArgList &Args); void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, @@ -916,6 +920,14 @@ public: void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S); void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S); + struct CXXTryStmtInfo { + llvm::BasicBlock *SavedLandingPad; + llvm::BasicBlock *HandlerBlock; + llvm::BasicBlock *FinallyBlock; + }; + CXXTryStmtInfo EnterCXXTryStmt(const CXXTryStmt &S); + void ExitCXXTryStmt(const CXXTryStmt &S, CXXTryStmtInfo Info); + void EmitCXXTryStmt(const CXXTryStmt &S); //===--------------------------------------------------------------------===// @@ -1326,6 +1338,10 @@ private: ArgType)); } } + + const TargetCodeGenInfo &getTargetHooks() const { + return CGM.getTargetCodeGenInfo(); + } }; diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 5a552c4..91c7322 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -316,24 +316,20 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, return CodeGenModule::GVA_CXXInline; } -/// SetFunctionDefinitionAttributes - Set attributes for a global. -/// -/// FIXME: This is currently only done for aliases and functions, but not for -/// variables (these details are set in EmitGlobalVarDefinition for variables). -void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D, - llvm::GlobalValue *GV) { +llvm::GlobalValue::LinkageTypes +CodeGenModule::getFunctionLinkage(const FunctionDecl *D) { GVALinkage Linkage = GetLinkageForFunction(getContext(), D, Features); if (Linkage == GVA_Internal) { - GV->setLinkage(llvm::Function::InternalLinkage); + return llvm::Function::InternalLinkage; } else if (D->hasAttr<DLLExportAttr>()) { - GV->setLinkage(llvm::Function::DLLExportLinkage); + return llvm::Function::DLLExportLinkage; } else if (D->hasAttr<WeakAttr>()) { - GV->setLinkage(llvm::Function::WeakAnyLinkage); + return llvm::Function::WeakAnyLinkage; } else if (Linkage == GVA_C99Inline) { // In C99 mode, 'inline' functions are guaranteed to have a strong // definition somewhere else, so we can use available_externally linkage. - GV->setLinkage(llvm::Function::AvailableExternallyLinkage); + return llvm::Function::AvailableExternallyLinkage; } else if (Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) { // In C++, the compiler has to emit a definition in every translation unit // that references the function. We should use linkonce_odr because @@ -341,13 +337,22 @@ void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D, // don't need to codegen it. b) if the function persists, it needs to be // merged with other definitions. c) C++ has the ODR, so we know the // definition is dependable. - GV->setLinkage(llvm::Function::LinkOnceODRLinkage); + return llvm::Function::LinkOnceODRLinkage; } else { assert(Linkage == GVA_StrongExternal); // Otherwise, we have strong external linkage. - GV->setLinkage(llvm::Function::ExternalLinkage); + return llvm::Function::ExternalLinkage; } +} + +/// SetFunctionDefinitionAttributes - Set attributes for a global. +/// +/// FIXME: This is currently only done for aliases and functions, but not for +/// variables (these details are set in EmitGlobalVarDefinition for variables). +void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D, + llvm::GlobalValue *GV) { + GV->setLinkage(getFunctionLinkage(D)); SetCommonAttributes(D, GV); } @@ -747,14 +752,20 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName, // A called constructor which has no definition or declaration need be // synthesized. else if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { - if (CD->isImplicit()) + if (CD->isImplicit()) { + assert (CD->isUsed()); DeferredDeclsToEmit.push_back(D); + } } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) { - if (DD->isImplicit()) + if (DD->isImplicit()) { + assert (DD->isUsed()); DeferredDeclsToEmit.push_back(D); + } } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { - if (MD->isCopyAssignment() && MD->isImplicit()) + if (MD->isCopyAssignment() && MD->isImplicit()) { + assert (MD->isUsed()); DeferredDeclsToEmit.push_back(D); + } } } @@ -1190,28 +1201,8 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { - const llvm::FunctionType *Ty; const FunctionDecl *D = cast<FunctionDecl>(GD.getDecl()); - - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { - bool isVariadic = D->getType()->getAs<FunctionProtoType>()->isVariadic(); - - Ty = getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), isVariadic); - } else { - Ty = cast<llvm::FunctionType>(getTypes().ConvertType(D->getType())); - - // As a special case, make sure that definitions of K&R function - // "type foo()" aren't declared as varargs (which forces the backend - // to do unnecessary work). - if (D->getType()->isFunctionNoProtoType()) { - assert(Ty->isVarArg() && "Didn't lower type as expected"); - // Due to stret, the lowered function could have arguments. - // Just create the same type as was lowered by ConvertType - // but strip off the varargs bit. - std::vector<const llvm::Type*> Args(Ty->param_begin(), Ty->param_end()); - Ty = llvm::FunctionType::get(Ty->getReturnType(), Args, false); - } - } + const llvm::FunctionType *Ty = getTypes().GetFunctionType(GD); // Get or create the prototype for the function. llvm::Constant *Entry = GetAddrOfFunction(GD, Ty); @@ -1342,6 +1333,7 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) { GA->setLinkage(llvm::Function::DLLExportLinkage); } } else if (D->hasAttr<WeakAttr>() || + D->hasAttr<WeakRefAttr>() || D->hasAttr<WeakImportAttr>()) { GA->setLinkage(llvm::Function::WeakAnyLinkage); } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 8280766..ac83326 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -206,6 +206,19 @@ public: /// GlobalValue. void setGlobalVisibility(llvm::GlobalValue *GV, const Decl *D) const; + llvm::Constant *GetAddrOfGlobal(GlobalDecl GD) { + if (isa<CXXConstructorDecl>(GD.getDecl())) + return GetAddrOfCXXConstructor(cast<CXXConstructorDecl>(GD.getDecl()), + GD.getCtorType()); + else if (isa<CXXDestructorDecl>(GD.getDecl())) + return GetAddrOfCXXDestructor(cast<CXXDestructorDecl>(GD.getDecl()), + GD.getDtorType()); + else if (isa<FunctionDecl>(GD.getDecl())) + return GetAddrOfFunction(GD); + else + return GetAddrOfGlobalVar(cast<VarDecl>(GD.getDecl())); + } + /// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the /// given global variable. If Ty is non-null and if the global doesn't exist, /// then it will be greated with the specified type instead of whatever the @@ -291,13 +304,13 @@ public: /// GetAddrOfCXXConstructor - Return the address of the constructor of the /// given type. - llvm::Function *GetAddrOfCXXConstructor(const CXXConstructorDecl *D, - CXXCtorType Type); + llvm::GlobalValue *GetAddrOfCXXConstructor(const CXXConstructorDecl *D, + CXXCtorType Type); /// GetAddrOfCXXDestructor - Return the address of the constructor of the /// given type. - llvm::Function *GetAddrOfCXXDestructor(const CXXDestructorDecl *D, - CXXDtorType Type); + llvm::GlobalValue *GetAddrOfCXXDestructor(const CXXDestructorDecl *D, + CXXDtorType Type); /// getBuiltinLibFunction - Given a builtin id for a function like /// "__builtin_fabsf", return a Function* for "fabsf". @@ -417,6 +430,9 @@ public: GVA_TemplateInstantiation }; + llvm::GlobalVariable::LinkageTypes + getFunctionLinkage(const FunctionDecl *FD); + /// getVtableLinkage - Return the appropriate linkage for the vtable, VTT, /// and type information of the given class. static llvm::GlobalVariable::LinkageTypes @@ -468,6 +484,9 @@ private: // C++ related functions. + bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target); + bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D); + void EmitNamespace(const NamespaceDecl *D); void EmitLinkageSpec(const LinkageSpecDecl *D); diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 3c20934..4feca4d 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -190,6 +190,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { #define ABSTRACT_TYPE(Class, Base) #define NON_CANONICAL_TYPE(Class, Base) case Type::Class: #define DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" assert(false && "Non-canonical or dependent types aren't possible."); break; @@ -313,10 +314,14 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { // The function type can be built; call the appropriate routines to // build it. if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(&Ty)) - return GetFunctionType(getFunctionInfo(FPT), FPT->isVariadic()); + return GetFunctionType(getFunctionInfo( + CanQual<FunctionProtoType>::CreateUnsafe(QualType(FPT,0))), + FPT->isVariadic()); const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(&Ty); - return GetFunctionType(getFunctionInfo(FNPT), true); + return GetFunctionType(getFunctionInfo( + CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(FNPT,0))), + true); } case Type::ObjCInterface: { @@ -386,9 +391,6 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { NULL); return PtrDiffTy; } - - case Type::TemplateSpecialization: - assert(false && "Dependent types can't get here"); } // FIXME: implement. diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 87ba0bc..b2912ef 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -35,6 +35,7 @@ namespace llvm { namespace clang { class ABIInfo; class ASTContext; + template <typename> class CanQual; class CXXConstructorDecl; class CXXDestructorDecl; class CXXMethodDecl; @@ -48,6 +49,7 @@ namespace clang { class TagDecl; class TargetInfo; class Type; + typedef CanQual<Type> CanQualType; namespace CodeGen { class CodeGenTypes; @@ -168,6 +170,8 @@ public: const llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info, bool IsVariadic); + const llvm::FunctionType *GetFunctionType(GlobalDecl GD); + /// GetFunctionTypeForVtable - Get the LLVM function type for use in a vtable, /// given a CXXMethodDecl. If the method to has an incomplete return type, @@ -184,11 +188,6 @@ public: /// replace the 'opaque' type we previously made for it if applicable. void UpdateCompletedType(const TagDecl *TD); -private: - const CGFunctionInfo &getFunctionInfo(const FunctionNoProtoType *FTNP); - const CGFunctionInfo &getFunctionInfo(const FunctionProtoType *FTP); - -public: /// getFunctionInfo - Get the function info for the specified function decl. const CGFunctionInfo &getFunctionInfo(GlobalDecl GD); @@ -205,6 +204,8 @@ public: return getFunctionInfo(Ty->getResultType(), Args, Ty->getCallConv(), Ty->getNoReturnAttr()); } + const CGFunctionInfo &getFunctionInfo(CanQual<FunctionProtoType> Ty); + const CGFunctionInfo &getFunctionInfo(CanQual<FunctionNoProtoType> Ty); // getFunctionInfo - Get the function info for a member function. const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD, @@ -221,8 +222,12 @@ public: const FunctionArgList &Args, CallingConv CC, bool NoReturn); - const CGFunctionInfo &getFunctionInfo(QualType RetTy, - const llvm::SmallVector<QualType, 16> &ArgTys, + + /// Retrieves the ABI information for the given function signature. + /// + /// \param ArgTys - must all actually be canonical as params + const CGFunctionInfo &getFunctionInfo(CanQualType RetTy, + const llvm::SmallVectorImpl<CanQualType> &ArgTys, CallingConv CC, bool NoReturn); diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index a302225..64743c7 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -455,7 +455,9 @@ void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) { mangleType(QualType(Qualifier->getAsType(), 0)); break; case NestedNameSpecifier::Identifier: - mangleUnresolvedScope(Qualifier->getPrefix()); + // Member expressions can have these without prefixes. + if (Qualifier->getPrefix()) + mangleUnresolvedScope(Qualifier->getPrefix()); mangleSourceName(Qualifier->getAsIdentifier()); break; } @@ -1123,6 +1125,42 @@ void CXXNameMangler::mangleType(const TypenameType *T) { Out << 'E'; } +void CXXNameMangler::mangleType(const TypeOfType *T) { + // FIXME: this is pretty unsatisfactory, but there isn't an obvious + // "extension with parameters" mangling. + Out << "u6typeof"; +} + +void CXXNameMangler::mangleType(const TypeOfExprType *T) { + // FIXME: this is pretty unsatisfactory, but there isn't an obvious + // "extension with parameters" mangling. + Out << "u6typeof"; +} + +void CXXNameMangler::mangleType(const DecltypeType *T) { + Expr *E = T->getUnderlyingExpr(); + + // type ::= Dt <expression> E # decltype of an id-expression + // # or class member access + // ::= DT <expression> E # decltype of an expression + + // This purports to be an exhaustive list of id-expressions and + // class member accesses. Note that we do not ignore parentheses; + // parentheses change the semantics of decltype for these + // expressions (and cause the mangler to use the other form). + if (isa<DeclRefExpr>(E) || + isa<MemberExpr>(E) || + isa<UnresolvedLookupExpr>(E) || + isa<DependentScopeDeclRefExpr>(E) || + isa<CXXDependentScopeMemberExpr>(E) || + isa<UnresolvedMemberExpr>(E)) + Out << "Dt"; + else + Out << "DT"; + mangleExpression(E); + Out << 'E'; +} + void CXXNameMangler::mangleIntegerLiteral(QualType T, const llvm::APSInt &Value) { // <expr-primary> ::= L <type> <value number> E # integer literal @@ -1163,20 +1201,14 @@ void CXXNameMangler::mangleCalledExpression(const Expr *E, unsigned Arity) { /// Mangles a member expression. Implicit accesses are not handled, /// but that should be okay, because you shouldn't be able to /// make an implicit access in a function template declaration. -/// -/// The standard ABI does not describe how member expressions should -/// be mangled, so this is very unstandardized. We mangle as if it -/// were a binary operator, except that the RHS is mangled as an -/// abstract name. -/// -/// The standard ABI also does not assign a mangling to the dot -/// operator, so we arbitrarily select 'me'. void CXXNameMangler::mangleMemberExpr(const Expr *Base, bool IsArrow, NestedNameSpecifier *Qualifier, DeclarationName Member, unsigned Arity) { - Out << (IsArrow ? "pt" : "me"); + // gcc-4.4 uses 'dt' for dot expressions, which is reasonable. + // OTOH, gcc also mangles the name as an expression. + Out << (IsArrow ? "pt" : "dt"); mangleExpression(Base); mangleUnresolvedName(Qualifier, Member, Arity); } @@ -1346,10 +1378,16 @@ void CXXNameMangler::mangleExpression(const Expr *E) { break; case Expr::DeclRefExprClass: { - const Decl *D = cast<DeclRefExpr>(E)->getDecl(); + const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl(); switch (D->getKind()) { - default: assert(false && "Unhandled decl kind!"); + default: + // <expr-primary> ::= L <mangled-name> E # external name + Out << 'L'; + mangle(D, "_Z"); + Out << 'E'; + break; + case Decl::NonTypeTemplateParm: { const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D); mangleTemplateParameter(PD->getIndex()); @@ -1363,7 +1401,18 @@ void CXXNameMangler::mangleExpression(const Expr *E) { case Expr::DependentScopeDeclRefExprClass: { const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E); - const Type *QTy = DRE->getQualifier()->getAsType(); + NestedNameSpecifier *NNS = DRE->getQualifier(); + const Type *QTy = NNS->getAsType(); + + // When we're dealing with a nested-name-specifier that has just a + // dependent identifier in it, mangle that as a typename. FIXME: + // It isn't clear that we ever actually want to have such a + // nested-name-specifier; why not just represent it as a typename type? + if (!QTy && NNS->getAsIdentifier() && NNS->getPrefix()) { + QTy = getASTContext().getTypenameType(NNS->getPrefix(), + NNS->getAsIdentifier()) + .getTypePtr(); + } assert(QTy && "Qualifier was not type!"); // ::= sr <type> <unqualified-name> # dependent name @@ -1648,6 +1697,9 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { if (const ClassTemplateSpecializationDecl *SD = dyn_cast<ClassTemplateSpecializationDecl>(ND)) { + if (!isStdNamespace(SD->getDeclContext())) + return false; + // <substitution> ::= Ss # ::std::basic_string<char, // ::std::char_traits<char>, // ::std::allocator<char> > diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index a7c0caa..f4ec914 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -972,12 +972,11 @@ ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty, return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } else if (CoerceTo == llvm::Type::getDoubleTy(CoerceTo->getContext())) { - // FIXME: It would probably be better to make CGFunctionInfo only map using - // canonical types than to canonize here. - QualType CTy = Context.getCanonicalType(Ty); + assert(Ty.isCanonical() && "should always have a canonical type here"); + assert(!Ty.hasQualifiers() && "should never have a qualified type here"); // Float and double end up in a single SSE reg. - if (CTy == Context.FloatTy || CTy == Context.DoubleTy) + if (Ty == Context.FloatTy || Ty == Context.DoubleTy) return ABIArgInfo::getDirect(); } @@ -1497,9 +1496,29 @@ ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty, llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const { - return 0; + const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(CGF.getLLVMContext())); + const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); + + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, + "ap"); + llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); + llvm::Type *PTy = + llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); + llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); + + uint64_t Offset = CGF.getContext().getTypeSize(Ty) / 8; + + llvm::Value *NextAddr = + Builder.CreateGEP(Addr, llvm::ConstantInt::get( + llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset), + "ap.next"); + Builder.CreateStore(NextAddr, VAListAddrAsBPP); + + return AddrTyped; } + // ARM ABI Implementation namespace { diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h index 58b7b79..9e80081 100644 --- a/lib/CodeGen/TargetInfo.h +++ b/lib/CodeGen/TargetInfo.h @@ -17,6 +17,7 @@ namespace llvm { class GlobalValue; + class Value; } namespace clang { @@ -25,6 +26,7 @@ namespace clang { namespace CodeGen { class CodeGenModule; + class CodeGenFunction; } /// TargetCodeGenInfo - This class organizes various target-specific @@ -44,6 +46,35 @@ namespace clang { /// target-specific attributes for the given global. virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { } + + /// Controls whether __builtin_extend_pointer should sign-extend + /// pointers to uint64_t or zero-extend them (the default). Has + /// no effect for targets: + /// - that have 64-bit pointers, or + /// - that cannot address through registers larger than pointers, or + /// - that implicitly ignore/truncate the top bits when addressing + /// through such registers. + virtual bool extendPointerWithSExt() const { return false; } + + /// Performs the code-generation required to convert a return + /// address as stored by the system into the actual address of the + /// next instruction that will be executed. + /// + /// Used by __builtin_extract_return_addr(). + virtual llvm::Value *decodeReturnAddress(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const { + return Address; + } + + /// Performs the code-generation required to convert the address + /// of an instruction into a return address suitable for storage + /// by the system in a return slot. + /// + /// Used by __builtin_frob_return_addr(). + virtual llvm::Value *encodeReturnAddress(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const { + return Address; + } }; } |