diff options
Diffstat (limited to 'lib/CodeGen/CGCXX.cpp')
-rw-r--r-- | lib/CodeGen/CGCXX.cpp | 1639 |
1 files changed, 1397 insertions, 242 deletions
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 5f3acea767d5..3960cf51868f 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -11,22 +11,123 @@ // //===----------------------------------------------------------------------===// -// We might split this into multiple files if it gets too unwieldy +// We might split this into multiple files if it gets too unwieldy #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "Mangle.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/StmtCXX.h" #include "llvm/ADT/StringExtras.h" using namespace clang; using namespace CodeGen; -void -CodeGenFunction::GenerateStaticCXXBlockVarDeclInit(const VarDecl &D, - llvm::GlobalVariable *GV) { +void +CodeGenFunction::EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor, + llvm::Constant *DeclPtr) { + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + + std::vector<const llvm::Type *> Params; + Params.push_back(Int8PtrTy); + + // Get the destructor function type + const llvm::Type *DtorFnTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); + DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy); + + Params.clear(); + Params.push_back(DtorFnTy); + Params.push_back(Int8PtrTy); + Params.push_back(Int8PtrTy); + + // Get the __cxa_atexit function type + // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d ); + const llvm::FunctionType *AtExitFnTy = + llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false); + + llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy, + "__cxa_atexit"); + + llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy, + "__dso_handle"); + + llvm::Constant *DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); + + llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy), + llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy), + llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) }; + Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args)); +} + +void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, + llvm::Constant *DeclPtr) { + assert(D.hasGlobalStorage() && + "VarDecl must have global storage!"); + + const Expr *Init = D.getInit(); + QualType T = D.getType(); + + if (T->isReferenceType()) { + ErrorUnsupported(Init, "global variable that binds to a reference"); + } else if (!hasAggregateLLVMType(T)) { + llvm::Value *V = EmitScalarExpr(Init); + EmitStoreOfScalar(V, DeclPtr, T.isVolatileQualified(), T); + } else if (T->isAnyComplexType()) { + EmitComplexExprIntoAddr(Init, DeclPtr, T.isVolatileQualified()); + } else { + EmitAggExpr(Init, DeclPtr, T.isVolatileQualified()); + + if (const RecordType *RT = T->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (!RD->hasTrivialDestructor()) + EmitCXXGlobalDtorRegistration(RD->getDestructor(getContext()), DeclPtr); + } + } +} + +void +CodeGenModule::EmitCXXGlobalInitFunc() { + if (CXXGlobalInits.empty()) + return; + + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + false); + + // Create our global initialization function. + // FIXME: Should this be tweakable by targets? + llvm::Function *Fn = + llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, + "__cxx_global_initialization", &TheModule); + + CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, + &CXXGlobalInits[0], + CXXGlobalInits.size()); + AddGlobalCtor(Fn); +} + +void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, + const VarDecl **Decls, + unsigned NumDecls) { + StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), + SourceLocation()); + + for (unsigned i = 0; i != NumDecls; ++i) { + const VarDecl *D = Decls[i]; + + llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D); + EmitCXXGlobalVarDeclInit(*D, DeclPtr); + } + FinishFunction(); +} + +void +CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, + llvm::GlobalVariable *GV) { // FIXME: This should use __cxa_guard_{acquire,release}? assert(!getContext().getLangOptions().ThreadsafeStatics && @@ -34,46 +135,37 @@ CodeGenFunction::GenerateStaticCXXBlockVarDeclInit(const VarDecl &D, llvm::SmallString<256> GuardVName; llvm::raw_svector_ostream GuardVOut(GuardVName); - mangleGuardVariable(&D, getContext(), GuardVOut); - + mangleGuardVariable(CGM.getMangleContext(), &D, GuardVOut); + // Create the guard variable. - llvm::GlobalValue *GuardV = - new llvm::GlobalVariable(llvm::Type::Int64Ty, false, + llvm::GlobalValue *GuardV = + new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), false, GV->getLinkage(), - llvm::Constant::getNullValue(llvm::Type::Int64Ty), - GuardVName.c_str(), - &CGM.getModule()); - + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)), + GuardVName.str()); + // Load the first byte of the guard variable. - const llvm::Type *PtrTy = llvm::PointerType::get(llvm::Type::Int8Ty, 0); - llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy), + const llvm::Type *PtrTy = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy), "tmp"); - + // Compare it against 0. - llvm::Value *nullValue = llvm::Constant::getNullValue(llvm::Type::Int8Ty); + llvm::Value *nullValue = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)); llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool"); - + llvm::BasicBlock *InitBlock = createBasicBlock("init"); llvm::BasicBlock *EndBlock = createBasicBlock("init.end"); // If the guard variable is 0, jump to the initializer code. Builder.CreateCondBr(ICmp, InitBlock, EndBlock); - + EmitBlock(InitBlock); - const Expr *Init = D.getInit(); - if (!hasAggregateLLVMType(Init->getType())) { - llvm::Value *V = EmitScalarExpr(Init); - Builder.CreateStore(V, GV, D.getType().isVolatileQualified()); - } else if (Init->getType()->isAnyComplexType()) { - EmitComplexExprIntoAddr(Init, GV, D.getType().isVolatileQualified()); - } else { - EmitAggExpr(Init, GV, D.getType().isVolatileQualified()); - } - - Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::Int8Ty, 1), + EmitCXXGlobalVarDeclInit(D, GV); + + Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1), Builder.CreateBitCast(GuardV, PtrTy)); - + EmitBlock(EndBlock); } @@ -82,336 +174,1399 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) { - assert(MD->isInstance() && + assert(MD->isInstance() && "Trying to emit a member call expr on a static method!"); - const FunctionProtoType *FPT = MD->getType()->getAsFunctionProtoType(); - + // A call to a trivial destructor requires no code generation. + if (const CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(MD)) + if (Destructor->isTrivial()) + return RValue::get(0); + + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + CallArgList Args; - + // Push the this ptr. Args.push_back(std::make_pair(RValue::get(This), MD->getThisType(getContext()))); - + // And the rest of the call args EmitCallArgs(Args, FPT, ArgBeg, ArgEnd); - - QualType ResultType = MD->getType()->getAsFunctionType()->getResultType(); + + QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, Args, MD); } +/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given +/// expr can be devirtualized. +static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) { + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { + // This is a record decl. We know the type and can devirtualize it. + return VD->getType()->isRecordType(); + } + + return false; + } + + // We can always devirtualize calls on temporary object expressions. + if (isa<CXXTemporaryObjectExpr>(Base)) + return true; + + // And calls on bound temporaries. + if (isa<CXXBindTemporaryExpr>(Base)) + return true; + + // Check if this is a call expr that returns a record type. + if (const CallExpr *CE = dyn_cast<CallExpr>(Base)) + return CE->getCallReturnType()->isRecordType(); + + // We can't devirtualize the call. + return false; +} + RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { + if (isa<BinaryOperator>(CE->getCallee())) + return EmitCXXMemberPointerCallExpr(CE); + const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()); const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); - const FunctionProtoType *FPT = MD->getType()->getAsFunctionProtoType(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Constant *Callee = CGM.GetAddrOfFunction(GlobalDecl(MD), Ty); + if (MD->isStatic()) { + // The method is static, emit it as we would a regular call. + llvm::Value *Callee = CGM.GetAddrOfFunction(MD); + return EmitCall(Callee, getContext().getPointerType(MD->getType()), + CE->arg_begin(), CE->arg_end(), 0); + + } + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); llvm::Value *This; - + if (ME->isArrow()) This = EmitScalarExpr(ME->getBase()); else { LValue BaseLV = EmitLValue(ME->getBase()); This = BaseLV.getAddress(); } - - return EmitCXXMemberCall(MD, Callee, This, + + // C++ [class.virtual]p12: + // Explicit qualification with the scope operator (5.1) suppresses the + // virtual call mechanism. + // + // We also don't emit a virtual call if the base expression has a record type + // because then we know what the type is. + llvm::Value *Callee; + if (MD->isVirtual() && !ME->hasQualifier() && + !canDevirtualizeMemberFunctionCalls(ME->getBase())) + Callee = BuildVirtualCall(MD, This, Ty); + else if (const CXXDestructorDecl *Destructor + = dyn_cast<CXXDestructorDecl>(MD)) + Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty); + else + Callee = CGM.GetAddrOfFunction(MD, Ty); + + return EmitCXXMemberCall(MD, Callee, This, CE->arg_begin(), CE->arg_end()); } -RValue -CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, - const CXXMethodDecl *MD) { - assert(MD->isInstance() && - "Trying to emit a member call expr on a static method!"); +RValue +CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E) { + const BinaryOperator *BO = cast<BinaryOperator>(E->getCallee()); + const Expr *BaseExpr = BO->getLHS(); + const Expr *MemFnExpr = BO->getRHS(); + const MemberPointerType *MPT = + MemFnExpr->getType()->getAs<MemberPointerType>(); + const FunctionProtoType *FPT = + MPT->getPointeeType()->getAs<FunctionProtoType>(); + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(cast<RecordType>(MPT->getClass())->getDecl()); + + const llvm::FunctionType *FTy = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), + FPT->isVariadic()); + + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + + // Get the member function pointer. + llvm::Value *MemFnPtr = + CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn"); + EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false); + + // Emit the 'this' pointer. + llvm::Value *This; - const FunctionProtoType *FPT = MD->getType()->getAsFunctionProtoType(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Constant *Callee = CGM.GetAddrOfFunction(GlobalDecl(MD), Ty); + if (BO->getOpcode() == BinaryOperator::PtrMemI) + This = EmitScalarExpr(BaseExpr); + else + This = EmitLValue(BaseExpr).getAddress(); - llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); + // Adjust it. + llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1); + Adj = Builder.CreateLoad(Adj, "mem.fn.adj"); + + llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr"); + Ptr = Builder.CreateGEP(Ptr, Adj, "adj"); + + This = Builder.CreateBitCast(Ptr, This->getType(), "this"); + + llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr"); + const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); + + llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn"); + + // If the LSB in the function pointer is 1, the function pointer points to + // a virtual function. + llvm::Value *IsVirtual + = Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1), + "and"); + + IsVirtual = Builder.CreateTrunc(IsVirtual, + llvm::Type::getInt1Ty(VMContext)); + + llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual"); + llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual"); + llvm::BasicBlock *FnEnd = createBasicBlock("fn.end"); + + Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual); + EmitBlock(FnVirtual); + + const llvm::Type *VTableTy = + FTy->getPointerTo()->getPointerTo()->getPointerTo(); + + llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy); + VTable = Builder.CreateLoad(VTable); + + VTable = Builder.CreateGEP(VTable, FnAsInt, "fn"); + + // Since the function pointer is 1 plus the virtual table offset, we + // subtract 1 by using a GEP. + VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1); + + llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn"); + + EmitBranch(FnEnd); + EmitBlock(FnNonVirtual); + + // If the function is not virtual, just load the pointer. + llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn"); + NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo()); + + EmitBlock(FnEnd); + + llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo()); + Callee->reserveOperandSpace(2); + Callee->addIncoming(VirtualFn, FnVirtual); + Callee->addIncoming(NonVirtualFn, FnNonVirtual); + + CallArgList Args; + + QualType ThisType = + getContext().getPointerType(getContext().getTagDeclType(RD)); + + // Push the this ptr. + Args.push_back(std::make_pair(RValue::get(This), ThisType)); + + // And the rest of the call args + EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end()); + QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType(); + return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), + Callee, Args, 0); +} + +RValue +CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, + const CXXMethodDecl *MD) { + assert(MD->isInstance() && + "Trying to emit a member call expr on a static method!"); + + if (MD->isCopyAssignment()) { + const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext()); + if (ClassDecl->hasTrivialCopyAssignment()) { + assert(!ClassDecl->hasUserDeclaredCopyAssignment() && + "EmitCXXOperatorMemberCallExpr - user declared copy assignment"); + llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); + llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress(); + QualType Ty = E->getType(); + EmitAggregateCopy(This, Src, Ty); + return RValue::get(This); + } + } + + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, Ty); + + llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); + return EmitCXXMemberCall(MD, Callee, This, E->arg_begin() + 1, E->arg_end()); } llvm::Value *CodeGenFunction::LoadCXXThis() { - assert(isa<CXXMethodDecl>(CurFuncDecl) && + 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'"); - + // 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"); } +/// EmitCXXAggrConstructorCall - This routine essentially creates a (nested) +/// for-loop to call the default constructor on individual members of the +/// array. +/// 'D' is the default constructor for elements of the array, 'ArrayTy' is the +/// array type and 'ArrayPtr' points to the beginning fo the array. +/// It is assumed that all relevant checks have been made by the caller. +void +CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, + const ConstantArrayType *ArrayTy, + llvm::Value *ArrayPtr) { + const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + llvm::Value * NumElements = + llvm::ConstantInt::get(SizeTy, + getContext().getConstantArrayElementCount(ArrayTy)); + + EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr); +} + +void +CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, + llvm::Value *NumElements, + llvm::Value *ArrayPtr) { + const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + + // Create a temporary for the loop index and initialize it with 0. + llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index"); + llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy); + Builder.CreateStore(Zero, IndexPtr, false); + + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); + + EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + + // Generate: if (loop-index < number-of-elements fall to the loop body, + // otherwise, go to the block after the for-loop. + llvm::Value *Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "isless"); + // If the condition is true, execute the body. + Builder.CreateCondBr(IsLess, ForBody, AfterFor); + + EmitBlock(ForBody); + + llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); + // Inside the loop body, emit the constructor call on the array element. + Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter, + "arrayidx"); + EmitCXXConstructorCall(D, Ctor_Complete, Address, 0, 0); + + EmitBlock(ContinueBlock); + + // Emit the increment of the loop counter. + llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 1); + Counter = Builder.CreateLoad(IndexPtr); + NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); + Builder.CreateStore(NextVal, IndexPtr, false); + + // Finally, branch back up to the condition for the next iteration. + EmitBranch(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor, true); +} + +/// EmitCXXAggrDestructorCall - calls the default destructor on array +/// elements in reverse order of construction. +void +CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, + const ArrayType *Array, + llvm::Value *This) { + const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); + assert(CA && "Do we support VLA for destruction ?"); + llvm::Value *One = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + 1); + uint64_t ElementCount = getContext().getConstantArrayElementCount(CA); + // Create a temporary for the loop index and initialize it with count of + // array elements. + llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), + "loop.index"); + // Index = ElementCount; + llvm::Value* UpperCount = + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), ElementCount); + Builder.CreateStore(UpperCount, IndexPtr, false); + + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); + + EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + + // Generate: if (loop-index != 0 fall to the loop body, + // otherwise, go to the block after the for-loop. + llvm::Value* zeroConstant = + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); + llvm::Value *Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant, + "isne"); + // If the condition is true, execute the body. + Builder.CreateCondBr(IsNE, ForBody, AfterFor); + + EmitBlock(ForBody); + + llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); + // Inside the loop body, emit the constructor call on the array element. + Counter = Builder.CreateLoad(IndexPtr); + Counter = Builder.CreateSub(Counter, One); + llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx"); + EmitCXXDestructorCall(D, Dtor_Complete, Address); + + EmitBlock(ContinueBlock); + + // Emit the decrement of the loop counter. + Counter = Builder.CreateLoad(IndexPtr); + Counter = Builder.CreateSub(Counter, One, "dec"); + Builder.CreateStore(Counter, IndexPtr, false); + + // Finally, branch back up to the condition for the next iteration. + EmitBranch(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor, true); +} + void -CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, - CXXCtorType Type, +CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, + CXXCtorType Type, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) { + if (D->isCopyConstructor(getContext())) { + const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext()); + if (ClassDecl->hasTrivialCopyConstructor()) { + assert(!ClassDecl->hasUserDeclaredCopyConstructor() && + "EmitCXXConstructorCall - user declared copy constructor"); + const Expr *E = (*ArgBeg); + QualType Ty = E->getType(); + llvm::Value *Src = EmitLValue(E).getAddress(); + EmitAggregateCopy(This, Src, Ty); + return; + } + } + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); EmitCXXMemberCall(D, Callee, This, ArgBeg, ArgEnd); } -void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *D, +void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type, llvm::Value *This) { llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(D, Type); - + EmitCXXMemberCall(D, Callee, This, 0, 0); } -void -CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, +void +CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E) { assert(Dest && "Must have a destination!"); - - const CXXRecordDecl *RD = - cast<CXXRecordDecl>(E->getType()->getAsRecordType()->getDecl()); + + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); if (RD->hasTrivialConstructor()) return; - - // Call the constructor. - EmitCXXConstructorCall(E->getConstructor(), Ctor_Complete, Dest, - E->arg_begin(), E->arg_end()); -} - -llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { - if (E->isArray()) { - ErrorUnsupported(E, "new[] expression"); - return llvm::UndefValue::get(ConvertType(E->getType())); - } - - QualType AllocType = E->getAllocatedType(); - FunctionDecl *NewFD = E->getOperatorNew(); - const FunctionProtoType *NewFTy = NewFD->getType()->getAsFunctionProtoType(); - - CallArgList NewArgs; - - // The allocation size is the first argument. - QualType SizeTy = getContext().getSizeType(); - llvm::Value *AllocSize = - llvm::ConstantInt::get(ConvertType(SizeTy), - getContext().getTypeSize(AllocType) / 8); - - NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy)); - - // Emit the rest of the arguments. - // FIXME: Ideally, this should just use EmitCallArgs. - CXXNewExpr::const_arg_iterator NewArg = E->placement_arg_begin(); - - // First, use the types from the function type. - // We start at 1 here because the first argument (the allocation size) - // has already been emitted. - for (unsigned i = 1, e = NewFTy->getNumArgs(); i != e; ++i, ++NewArg) { - QualType ArgType = NewFTy->getArgType(i); - - assert(getContext().getCanonicalType(ArgType.getNonReferenceType()). - getTypePtr() == - getContext().getCanonicalType(NewArg->getType()).getTypePtr() && - "type mismatch in call argument!"); - - NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType), - ArgType)); - - } - - // Either we've emitted all the call args, or we have a call to a - // variadic function. - assert((NewArg == E->placement_arg_end() || NewFTy->isVariadic()) && - "Extra arguments in non-variadic function!"); - - // If we still have any arguments, emit them using the type of the argument. - for (CXXNewExpr::const_arg_iterator NewArgEnd = E->placement_arg_end(); - NewArg != NewArgEnd; ++NewArg) { - QualType ArgType = NewArg->getType(); - NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType), - ArgType)); - } - - // Emit the call to new. - RValue RV = - EmitCall(CGM.getTypes().getFunctionInfo(NewFTy->getResultType(), NewArgs), - CGM.GetAddrOfFunction(GlobalDecl(NewFD)), - NewArgs, NewFD); - - // If an allocation function is declared with an empty exception specification - // it returns null to indicate failure to allocate storage. [expr.new]p13. - // (We don't need to check for null when there's no new initializer and - // we're allocating a POD type). - bool NullCheckResult = NewFTy->hasEmptyExceptionSpec() && - !(AllocType->isPODType() && !E->hasInitializer()); - - llvm::BasicBlock *NewNull = 0; - llvm::BasicBlock *NewNotNull = 0; - llvm::BasicBlock *NewEnd = 0; - - llvm::Value *NewPtr = RV.getScalarVal(); - - if (NullCheckResult) { - NewNull = createBasicBlock("new.null"); - NewNotNull = createBasicBlock("new.notnull"); - NewEnd = createBasicBlock("new.end"); - - llvm::Value *IsNull = - Builder.CreateICmpEQ(NewPtr, - llvm::Constant::getNullValue(NewPtr->getType()), - "isnull"); - - Builder.CreateCondBr(IsNull, NewNull, NewNotNull); - EmitBlock(NewNotNull); - } - - NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType())); - - if (AllocType->isPODType()) { - if (E->getNumConstructorArgs() > 0) { - assert(E->getNumConstructorArgs() == 1 && - "Can only have one argument to initializer of POD type."); - - const Expr *Init = E->getConstructorArg(0); - - if (!hasAggregateLLVMType(AllocType)) - Builder.CreateStore(EmitScalarExpr(Init), NewPtr); - else if (AllocType->isAnyComplexType()) - EmitComplexExprIntoAddr(Init, NewPtr, AllocType.isVolatileQualified()); - else - EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified()); - } - } else { - // Call the constructor. - CXXConstructorDecl *Ctor = E->getConstructor(); - - EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr, - E->constructor_arg_begin(), - E->constructor_arg_end()); - } - - if (NullCheckResult) { - Builder.CreateBr(NewEnd); - EmitBlock(NewNull); - Builder.CreateBr(NewEnd); - EmitBlock(NewEnd); - - llvm::PHINode *PHI = Builder.CreatePHI(NewPtr->getType()); - PHI->reserveOperandSpace(2); - PHI->addIncoming(NewPtr, NewNotNull); - PHI->addIncoming(llvm::Constant::getNullValue(NewPtr->getType()), NewNull); - - NewPtr = PHI; - } - - return NewPtr; -} -static bool canGenerateCXXstructor(const CXXRecordDecl *RD, - ASTContext &Context) { - // The class has base classes - we don't support that right now. - if (RD->getNumBases() > 0) - return false; - - for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); - I != E; ++I) { - // We don't support ctors for fields that aren't POD. - if (!I->getType()->isPODType()) - return false; + // Code gen optimization to eliminate copy constructor and return + // its first argument instead. + if (getContext().getLangOptions().ElideConstructors && E->isElidable()) { + CXXConstructExpr::const_arg_iterator i = E->arg_begin(); + EmitAggExpr((*i), Dest, false); + return; } - - return true; + // Call the constructor. + EmitCXXConstructorCall(E->getConstructor(), Ctor_Complete, Dest, + E->arg_begin(), E->arg_end()); } void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) { - if (!canGenerateCXXstructor(D->getParent(), getContext())) { - ErrorUnsupported(D, "C++ constructor", true); - return; - } - EmitGlobal(GlobalDecl(D, Ctor_Complete)); EmitGlobal(GlobalDecl(D, Ctor_Base)); } -void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D, +void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type) { - + llvm::Function *Fn = GetAddrOfCXXConstructor(D, Type); - - CodeGenFunction(*this).GenerateCode(D, Fn); - + + CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn); + SetFunctionDefinitionAttributes(D, Fn); SetLLVMFunctionAttributesForDefinition(D, Fn); } llvm::Function * -CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D, +CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type) { const llvm::FunctionType *FTy = getTypes().GetFunctionType(getTypes().getFunctionInfo(D), false); - + const char *Name = getMangledCXXCtorName(D, Type); return cast<llvm::Function>( GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type))); } -const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D, +const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D, CXXCtorType Type) { llvm::SmallString<256> Name; llvm::raw_svector_ostream Out(Name); - mangleCXXCtor(D, Type, Context, Out); - + mangleCXXCtor(getMangleContext(), D, Type, Out); + Name += '\0'; return UniqueMangledName(Name.begin(), Name.end()); } void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { - if (!canGenerateCXXstructor(D->getParent(), getContext())) { - ErrorUnsupported(D, "C++ destructor", true); - return; - } - EmitCXXDestructor(D, Dtor_Complete); EmitCXXDestructor(D, Dtor_Base); } -void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D, +void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type) { llvm::Function *Fn = GetAddrOfCXXDestructor(D, Type); - - CodeGenFunction(*this).GenerateCode(D, Fn); - + + CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn); + SetFunctionDefinitionAttributes(D, Fn); SetLLVMFunctionAttributesForDefinition(D, Fn); } llvm::Function * -CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D, +CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type) { const llvm::FunctionType *FTy = getTypes().GetFunctionType(getTypes().getFunctionInfo(D), false); - + const char *Name = getMangledCXXDtorName(D, Type); return cast<llvm::Function>( GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type))); } -const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D, +const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D, CXXDtorType Type) { llvm::SmallString<256> Name; llvm::raw_svector_ostream Out(Name); - mangleCXXDtor(D, Type, Context, Out); - + mangleCXXDtor(getMangleContext(), D, Type, Out); + Name += '\0'; return UniqueMangledName(Name.begin(), Name.end()); } + +llvm::Constant *CodeGenFunction::GenerateThunk(llvm::Function *Fn, + const CXXMethodDecl *MD, + bool Extern, int64_t nv, + int64_t v) { + QualType R = MD->getType()->getAs<FunctionType>()->getResultType(); + + FunctionArgList Args; + ImplicitParamDecl *ThisDecl = + ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + MD->getThisType(getContext())); + Args.push_back(std::make_pair(ThisDecl, ThisDecl->getType())); + for (FunctionDecl::param_const_iterator i = MD->param_begin(), + e = MD->param_end(); + i != e; ++i) { + ParmVarDecl *D = *i; + Args.push_back(std::make_pair(D, D->getType())); + } + IdentifierInfo *II + = &CGM.getContext().Idents.get("__thunk_named_foo_"); + FunctionDecl *FD = FunctionDecl::Create(getContext(), + getContext().getTranslationUnitDecl(), + SourceLocation(), II, R, 0, + Extern + ? FunctionDecl::Extern + : FunctionDecl::Static, + false, true); + StartFunction(FD, R, Fn, Args, SourceLocation()); + // FIXME: generate body + FinishFunction(); + return Fn; +} + +llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, + const CXXMethodDecl *MD, + bool Extern, + int64_t nv_t, + int64_t v_t, + int64_t nv_r, + int64_t v_r) { + QualType R = MD->getType()->getAs<FunctionType>()->getResultType(); + + FunctionArgList Args; + ImplicitParamDecl *ThisDecl = + ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, + MD->getThisType(getContext())); + Args.push_back(std::make_pair(ThisDecl, ThisDecl->getType())); + for (FunctionDecl::param_const_iterator i = MD->param_begin(), + e = MD->param_end(); + i != e; ++i) { + ParmVarDecl *D = *i; + Args.push_back(std::make_pair(D, D->getType())); + } + IdentifierInfo *II + = &CGM.getContext().Idents.get("__thunk_named_foo_"); + FunctionDecl *FD = FunctionDecl::Create(getContext(), + getContext().getTranslationUnitDecl(), + SourceLocation(), II, R, 0, + Extern + ? FunctionDecl::Extern + : FunctionDecl::Static, + false, true); + StartFunction(FD, R, Fn, Args, SourceLocation()); + // FIXME: generate body + FinishFunction(); + return Fn; +} + +llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, + int64_t nv, int64_t v) { + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleThunk(getMangleContext(), MD, nv, v, Out); + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::WeakAnyLinkage; + if (!Extern) + linktype = llvm::GlobalValue::InternalLinkage; + llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::FunctionType *FTy = + getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + + llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(), + &getModule()); + CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, nv, v); + // Fn = Builder.CreateBitCast(Fn, Ptr8Ty); + llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); + return m; +} + +llvm::Constant *CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD, + bool Extern, int64_t nv_t, + int64_t v_t, int64_t nv_r, + int64_t v_r) { + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleCovariantThunk(getMangleContext(), MD, nv_t, v_t, nv_r, v_r, Out); + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::WeakAnyLinkage; + if (!Extern) + linktype = llvm::GlobalValue::InternalLinkage; + llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::FunctionType *FTy = + getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + + llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(), + &getModule()); + CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, nv_t, v_t, nv_r, + v_r); + // Fn = Builder.CreateBitCast(Fn, Ptr8Ty); + llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); + return m; +} + +llvm::Value * +CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl) { + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + + llvm::Value *VTablePtr = Builder.CreateBitCast(This, + Int8PtrTy->getPointerTo()); + VTablePtr = Builder.CreateLoad(VTablePtr, "vtable"); + + int64_t VBaseOffsetIndex = + CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl); + + llvm::Value *VBaseOffsetPtr = + Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr"); + const llvm::Type *PtrDiffTy = + ConvertType(getContext().getPointerDiffType()); + + VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr, + PtrDiffTy->getPointerTo()); + + llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset"); + + return VBaseOffset; +} + +llvm::Value * +CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *&This, + const llvm::Type *Ty) { + int64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD); + + Ty = llvm::PointerType::get(Ty, 0); + Ty = llvm::PointerType::get(Ty, 0); + Ty = llvm::PointerType::get(Ty, 0); + llvm::Value *vtbl = Builder.CreateBitCast(This, Ty); + vtbl = Builder.CreateLoad(vtbl); + llvm::Value *vfn = Builder.CreateConstInBoundsGEP1_64(vtbl, + Index, "vfn"); + vfn = Builder.CreateLoad(vfn); + return vfn; +} + +/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class +/// array of objects from SrcValue to DestValue. Copying can be either a bitwise +/// copy or via a copy constructor call. +// FIXME. Consolidate this with EmitCXXAggrConstructorCall. +void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, + llvm::Value *Src, + const ArrayType *Array, + const CXXRecordDecl *BaseClassDecl, + QualType Ty) { + const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); + assert(CA && "VLA cannot be copied over"); + bool BitwiseCopy = BaseClassDecl->hasTrivialCopyConstructor(); + + // Create a temporary for the loop index and initialize it with 0. + llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), + "loop.index"); + llvm::Value* zeroConstant = + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); + Builder.CreateStore(zeroConstant, IndexPtr, false); + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); + + EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + // Generate: if (loop-index < number-of-elements fall to the loop body, + // otherwise, go to the block after the for-loop. + uint64_t NumElements = getContext().getConstantArrayElementCount(CA); + llvm::Value * NumElementsPtr = + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); + llvm::Value *Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr, + "isless"); + // If the condition is true, execute the body. + Builder.CreateCondBr(IsLess, ForBody, AfterFor); + + EmitBlock(ForBody); + llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); + // Inside the loop body, emit the constructor call on the array element. + Counter = Builder.CreateLoad(IndexPtr); + Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); + Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); + if (BitwiseCopy) + EmitAggregateCopy(Dest, Src, Ty); + else if (CXXConstructorDecl *BaseCopyCtor = + BaseClassDecl->getCopyConstructor(getContext(), 0)) { + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, + Ctor_Complete); + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + BaseCopyCtor->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + BaseCopyCtor->getParamDecl(0)->getType())); + QualType ResultType = + BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, BaseCopyCtor); + } + EmitBlock(ContinueBlock); + + // Emit the increment of the loop counter. + llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); + Counter = Builder.CreateLoad(IndexPtr); + NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); + Builder.CreateStore(NextVal, IndexPtr, false); + + // Finally, branch back up to the condition for the next iteration. + EmitBranch(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor, true); +} + +/// EmitClassAggrCopyAssignment - This routine generates code to assign a class +/// array of objects from SrcValue to DestValue. Assignment can be either a +/// bitwise assignment or via a copy assignment operator function call. +/// FIXME. This can be consolidated with EmitClassAggrMemberwiseCopy +void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, + llvm::Value *Src, + const ArrayType *Array, + const CXXRecordDecl *BaseClassDecl, + QualType Ty) { + const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); + assert(CA && "VLA cannot be asssigned"); + bool BitwiseAssign = BaseClassDecl->hasTrivialCopyAssignment(); + + // Create a temporary for the loop index and initialize it with 0. + llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), + "loop.index"); + llvm::Value* zeroConstant = + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); + Builder.CreateStore(zeroConstant, IndexPtr, false); + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); + + EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + // Generate: if (loop-index < number-of-elements fall to the loop body, + // otherwise, go to the block after the for-loop. + uint64_t NumElements = getContext().getConstantArrayElementCount(CA); + llvm::Value * NumElementsPtr = + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); + llvm::Value *Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr, + "isless"); + // If the condition is true, execute the body. + Builder.CreateCondBr(IsLess, ForBody, AfterFor); + + EmitBlock(ForBody); + llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); + // Inside the loop body, emit the assignment operator call on array element. + Counter = Builder.CreateLoad(IndexPtr); + Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); + Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); + const CXXMethodDecl *MD = 0; + if (BitwiseAssign) + EmitAggregateCopy(Dest, Src, Ty); + else { + bool hasCopyAssign = BaseClassDecl->hasConstCopyAssignment(getContext(), + MD); + assert(hasCopyAssign && "EmitClassAggrCopyAssignment - No user assign"); + (void)hasCopyAssign; + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::Type *LTy = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); + + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + MD->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + MD->getParamDecl(0)->getType())); + QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, MD); + } + EmitBlock(ContinueBlock); + + // Emit the increment of the loop counter. + llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); + Counter = Builder.CreateLoad(IndexPtr); + NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); + Builder.CreateStore(NextVal, IndexPtr, false); + + // Finally, branch back up to the condition for the next iteration. + EmitBranch(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor, true); +} + +/// EmitClassMemberwiseCopy - This routine generates code to copy a class +/// object from SrcValue to DestValue. Copying can be either a bitwise copy +/// or via a copy constructor call. +void CodeGenFunction::EmitClassMemberwiseCopy( + llvm::Value *Dest, llvm::Value *Src, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, QualType Ty) { + if (ClassDecl) { + Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + } + if (BaseClassDecl->hasTrivialCopyConstructor()) { + EmitAggregateCopy(Dest, Src, Ty); + return; + } + + if (CXXConstructorDecl *BaseCopyCtor = + BaseClassDecl->getCopyConstructor(getContext(), 0)) { + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, + Ctor_Complete); + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + BaseCopyCtor->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + BaseCopyCtor->getParamDecl(0)->getType())); + QualType ResultType = + BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, BaseCopyCtor); + } +} + +/// EmitClassCopyAssignment - This routine generates code to copy assign a class +/// object from SrcValue to DestValue. Assignment can be either a bitwise +/// assignment of via an assignment operator call. +// FIXME. Consolidate this with EmitClassMemberwiseCopy as they share a lot. +void CodeGenFunction::EmitClassCopyAssignment( + llvm::Value *Dest, llvm::Value *Src, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl, + QualType Ty) { + if (ClassDecl) { + Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + } + if (BaseClassDecl->hasTrivialCopyAssignment()) { + EmitAggregateCopy(Dest, Src, Ty); + return; + } + + const CXXMethodDecl *MD = 0; + bool ConstCopyAssignOp = BaseClassDecl->hasConstCopyAssignment(getContext(), + MD); + assert(ConstCopyAssignOp && "EmitClassCopyAssignment - missing copy assign"); + (void)ConstCopyAssignOp; + + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::Type *LTy = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); + + CallArgList CallArgs; + // Push the this (Dest) ptr. + CallArgs.push_back(std::make_pair(RValue::get(Dest), + MD->getThisType(getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + MD->getParamDecl(0)->getType())); + QualType ResultType = + MD->getType()->getAs<FunctionType>()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, MD); +} + +/// SynthesizeDefaultConstructor - synthesize a default constructor +void +CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + llvm::Function *Fn, + const FunctionArgList &Args) { + 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 +/// copy of its subobjects. The order of copying is the same as the order +/// of initialization of bases and members in a user-defined constructor +/// Each subobject is copied in the manner appropriate to its type: +/// if the subobject is of class type, the copy constructor for the class is +/// used; +/// if the subobject is an array, each element is copied, in the manner +/// appropriate to the element type; +/// if the subobject is of scalar type, the built-in assignment operator is +/// used. +/// Virtual base class subobjects shall be copied only once by the +/// implicitly-defined copy constructor + +void +CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + llvm::Function *Fn, + const FunctionArgList &Args) { + const CXXRecordDecl *ClassDecl = Ctor->getParent(); + assert(!ClassDecl->hasUserDeclaredCopyConstructor() && + "SynthesizeCXXCopyConstructor - copy constructor has definition already"); + StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, + SourceLocation()); + + FunctionArgList::const_iterator i = Args.begin(); + const VarDecl *ThisArg = i->first; + llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); + llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); + const VarDecl *SrcArg = (i+1)->first; + llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); + llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); + + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + // FIXME. copy constrution of virtual base NYI + if (Base->isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + EmitClassMemberwiseCopy(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, + Base->getType()); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = getContext().getCanonicalType((*Field)->getType()); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + + if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { + CXXRecordDecl *FieldClassDecl + = cast<CXXRecordDecl>(FieldClassType->getDecl()); + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *DestBaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + llvm::Value *SrcBaseAddrPtr = + Builder.CreateBitCast(RHS.getAddress(), BasePtr); + EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array, + FieldClassDecl, FieldType); + } + else + EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(), + 0 /*ClassDecl*/, FieldClassDecl, FieldType); + continue; + } + // Do a built-in assignment of scalar data members. + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + RValue RVRHS = EmitLoadOfLValue(RHS, FieldType); + EmitStoreThroughLValue(RVRHS, LHS, FieldType); + } + FinishFunction(); +} + +/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator. +/// Before the implicitly-declared copy assignment operator for a class is +/// implicitly defined, all implicitly- declared copy assignment operators for +/// its direct base classes and its nonstatic data members shall have been +/// implicitly defined. [12.8-p12] +/// The implicitly-defined copy assignment operator for class X performs +/// memberwise assignment of its subob- jects. The direct base classes of X are +/// assigned first, in the order of their declaration in +/// the base-specifier-list, and then the immediate nonstatic data members of X +/// are assigned, in the order in which they were declared in the class +/// definition.Each subobject is assigned in the manner appropriate to its type: +/// if the subobject is of class type, the copy assignment operator for the +/// class is used (as if by explicit qualification; that is, ignoring any +/// possible virtual overriding functions in more derived classes); +/// +/// if the subobject is an array, each element is assigned, in the manner +/// appropriate to the element type; +/// +/// 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) { + + 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; + llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); + llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); + const VarDecl *SrcArg = (i+1)->first; + llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); + llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); + + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + // FIXME. copy assignment of virtual base NYI + if (Base->isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, + Base->getType()); + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = getContext().getCanonicalType((*Field)->getType()); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + + if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { + CXXRecordDecl *FieldClassDecl + = cast<CXXRecordDecl>(FieldClassType->getDecl()); + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *DestBaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + llvm::Value *SrcBaseAddrPtr = + Builder.CreateBitCast(RHS.getAddress(), BasePtr); + EmitClassAggrCopyAssignment(DestBaseAddrPtr, SrcBaseAddrPtr, Array, + FieldClassDecl, FieldType); + } + else + EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(), + 0 /*ClassDecl*/, FieldClassDecl, FieldType); + continue; + } + // Do a built-in assignment of scalar data members. + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); + RValue RVRHS = EmitLoadOfLValue(RHS, FieldType); + EmitStoreThroughLValue(RVRHS, LHS, FieldType); + } + + // return *this; + Builder.CreateStore(LoadOfThis, ReturnValue); + + FinishFunction(); +} + +/// EmitCtorPrologue - This routine generates necessary code to initialize +/// base classes and non-static data members belonging to this constructor. +/// FIXME: This needs to take a CXXCtorType. +void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, + CXXCtorType CtorType) { + const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext()); + // FIXME: Add vbase initialization + llvm::Value *LoadOfThis = 0; + + for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(), + E = CD->init_end(); + B != E; ++B) { + CXXBaseOrMemberInitializer *Member = (*B); + if (Member->isBaseInitializer()) { + LoadOfThis = LoadCXXThis(); + Type *BaseType = Member->getBaseClass(); + CXXRecordDecl *BaseClassDecl = + cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); + llvm::Value *V = GetAddressCXXOfBaseClass(LoadOfThis, ClassDecl, + BaseClassDecl, + /*NullCheckValue=*/false); + EmitCXXConstructorCall(Member->getConstructor(), + CtorType, V, + Member->const_arg_begin(), + Member->const_arg_end()); + } else { + // non-static data member initilaizers. + FieldDecl *Field = Member->getMember(); + QualType FieldType = getContext().getCanonicalType((Field)->getType()); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + + LoadOfThis = LoadCXXThis(); + LValue LHS; + if (FieldType->isReferenceType()) { + // FIXME: This is really ugly; should be refactored somehow + unsigned idx = CGM.getTypes().getLLVMFieldNo(Field); + llvm::Value *V = Builder.CreateStructGEP(LoadOfThis, idx, "tmp"); + assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs"); + LHS = LValue::MakeAddr(V, MakeQualifiers(FieldType)); + } else { + LHS = EmitLValueForField(LoadOfThis, Field, false, 0); + } + if (FieldType->getAs<RecordType>()) { + if (!Field->isAnonymousStructOrUnion()) { + assert(Member->getConstructor() && + "EmitCtorPrologue - no constructor to initialize member"); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + EmitCXXAggrConstructorCall(Member->getConstructor(), + Array, BaseAddrPtr); + } + else + EmitCXXConstructorCall(Member->getConstructor(), + Ctor_Complete, LHS.getAddress(), + Member->const_arg_begin(), + Member->const_arg_end()); + continue; + } + else { + // Initializing an anonymous union data member. + FieldDecl *anonMember = Member->getAnonUnionMember(); + LHS = EmitLValueForField(LHS.getAddress(), anonMember, + /*IsUnion=*/true, 0); + FieldType = anonMember->getType(); + } + } + + assert(Member->getNumArgs() == 1 && "Initializer count must be 1 only"); + Expr *RhsExpr = *Member->arg_begin(); + RValue RHS; + if (FieldType->isReferenceType()) + RHS = EmitReferenceBindingToExpr(RhsExpr, FieldType, + /*IsInitializer=*/true); + else + RHS = RValue::get(EmitScalarExpr(RhsExpr, true)); + EmitStoreThroughLValue(RHS, LHS, FieldType); + } + } + + if (!CD->getNumBaseOrMemberInitializers() && !CD->isTrivial()) { + // Nontrivial default constructor with no initializer list. It may still + // have bases classes and/or contain non-static data members which require + // construction. + for (CXXRecordDecl::base_class_const_iterator Base = + ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + // FIXME. copy assignment of virtual base NYI + if (Base->isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (BaseClassDecl->hasTrivialConstructor()) + continue; + if (CXXConstructorDecl *BaseCX = + BaseClassDecl->getDefaultConstructor(getContext())) { + LoadOfThis = LoadCXXThis(); + llvm::Value *V = GetAddressCXXOfBaseClass(LoadOfThis, ClassDecl, + BaseClassDecl, + /*NullCheckValue=*/false); + EmitCXXConstructorCall(BaseCX, Ctor_Complete, V, 0, 0); + } + } + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = getContext().getCanonicalType((*Field)->getType()); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + if (!FieldType->getAs<RecordType>() || Field->isAnonymousStructOrUnion()) + continue; + const RecordType *ClassRec = FieldType->getAs<RecordType>(); + CXXRecordDecl *MemberClassDecl = + dyn_cast<CXXRecordDecl>(ClassRec->getDecl()); + if (!MemberClassDecl || MemberClassDecl->hasTrivialConstructor()) + continue; + if (CXXConstructorDecl *MamberCX = + MemberClassDecl->getDefaultConstructor(getContext())) { + LoadOfThis = LoadCXXThis(); + LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + EmitCXXAggrConstructorCall(MamberCX, Array, BaseAddrPtr); + } + else + EmitCXXConstructorCall(MamberCX, Ctor_Complete, LHS.getAddress(), + 0, 0); + } + } + } + + // Initialize the vtable pointer + if (ClassDecl->isDynamicClass()) { + if (!LoadOfThis) + LoadOfThis = LoadCXXThis(); + llvm::Value *VtableField; + llvm::Type *Ptr8Ty, *PtrPtr8Ty; + Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0); + VtableField = Builder.CreateBitCast(LoadOfThis, PtrPtr8Ty); + llvm::Value *vtable = GenerateVtable(ClassDecl); + Builder.CreateStore(vtable, VtableField); + } +} + +/// 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) { + const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DD->getDeclContext()); + assert(!ClassDecl->getNumVBases() && + "FIXME: Destruction of virtual bases not supported"); + (void)ClassDecl; // prevent warning. + + for (CXXDestructorDecl::destr_const_iterator *B = DD->destr_begin(), + *E = DD->destr_end(); B != E; ++B) { + uintptr_t BaseOrMember = (*B); + if (DD->isMemberToDestroy(BaseOrMember)) { + FieldDecl *FD = DD->getMemberToDestroy(BaseOrMember); + QualType FieldType = getContext().getCanonicalType((FD)->getType()); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + const RecordType *RT = FieldType->getAs<RecordType>(); + CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (FieldClassDecl->hasTrivialDestructor()) + continue; + llvm::Value *LoadOfThis = LoadCXXThis(); + LValue LHS = EmitLValueForField(LoadOfThis, FD, false, 0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()), + Array, BaseAddrPtr); + } + else + EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()), + Dtor_Complete, LHS.getAddress()); + } else { + const RecordType *RT = + DD->getAnyBaseClassToDestroy(BaseOrMember)->getAs<RecordType>(); + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (BaseClassDecl->hasTrivialDestructor()) + continue; + llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(), + ClassDecl, BaseClassDecl, + /*NullCheckValue=*/false); + EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()), + DtorType, V); + } + } + if (DD->getNumBaseOrMemberDestructions() || DD->isTrivial()) + return; + // Case of destructor synthesis with fields and base classes + // which have non-trivial destructors. They must be destructed in + // reverse order of their construction. + llvm::SmallVector<FieldDecl *, 16> DestructedFields; + + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + QualType FieldType = getContext().getCanonicalType((*Field)->getType()); + if (getContext().getAsConstantArrayType(FieldType)) + FieldType = getContext().getBaseElementType(FieldType); + if (const RecordType *RT = FieldType->getAs<RecordType>()) { + CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (FieldClassDecl->hasTrivialDestructor()) + continue; + DestructedFields.push_back(*Field); + } + } + if (!DestructedFields.empty()) + for (int i = DestructedFields.size() -1; i >= 0; --i) { + FieldDecl *Field = DestructedFields[i]; + QualType FieldType = Field->getType(); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + const RecordType *RT = FieldType->getAs<RecordType>(); + CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + llvm::Value *LoadOfThis = LoadCXXThis(); + LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(LHS.getAddress(), BasePtr); + EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()), + Array, BaseAddrPtr); + } + else + EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()), + Dtor_Complete, LHS.getAddress()); + } + + llvm::SmallVector<CXXRecordDecl*, 4> DestructedBases; + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + // FIXME. copy assignment of virtual base NYI + if (Base->isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (BaseClassDecl->hasTrivialDestructor()) + continue; + DestructedBases.push_back(BaseClassDecl); + } + if (DestructedBases.empty()) + return; + for (int i = DestructedBases.size() -1; i >= 0; --i) { + CXXRecordDecl *BaseClassDecl = DestructedBases[i]; + llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(), + ClassDecl,BaseClassDecl, + /*NullCheckValue=*/false); + EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()), + Dtor_Complete, V); + } +} + +void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, + CXXDtorType DtorType, + llvm::Function *Fn, + const FunctionArgList &Args) { + + const CXXRecordDecl *ClassDecl = Dtor->getParent(); + assert(!ClassDecl->hasUserDeclaredDestructor() && + "SynthesizeDefaultDestructor - destructor has user declaration"); + (void) ClassDecl; + + StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args, + SourceLocation()); + EmitDtorEpilogue(Dtor, DtorType); + FinishFunction(); +} + +// FIXME: Move this to CGCXXStmt.cpp +void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { + // FIXME: We need to do more here. + EmitStmt(S.getTryBlock()); +} |