diff options
Diffstat (limited to 'lib/CodeGen')
30 files changed, 2874 insertions, 1433 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 2df779c..9e44db0 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -296,7 +296,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { ++helpersize; continue; } else - E = new (getContext()) DeclRefExpr (cast<NamedDecl>(VD), + E = new (getContext()) DeclRefExpr (VD, VD->getType(), SourceLocation()); } @@ -1136,36 +1136,38 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, } llvm::Constant *BlockFunction::BuildbyrefCopyHelper(const llvm::Type *T, - int flag, unsigned Align) { - // All alignments below that of pointer alignment collpase down to just + int Flag, unsigned Align) { + // All alignments below that of pointer alignment collapse down to just // pointer alignment, as we always have at least that much alignment to begin // with. Align /= unsigned(CGF.Target.getPointerAlign(0)/8); + // As an optimization, we only generate a single function of each kind we // might need. We need a different one for each alignment and for each // setting of flags. We mix Align and flag to get the kind. - uint64_t kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + flag; - llvm::Constant *& Entry = CGM.AssignCache[kind]; + uint64_t Kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + Flag; + llvm::Constant *&Entry = CGM.AssignCache[Kind]; if (Entry) return Entry; - return Entry=CodeGenFunction(CGM).GeneratebyrefCopyHelperFunction(T, flag); + return Entry = CodeGenFunction(CGM).GeneratebyrefCopyHelperFunction(T, Flag); } llvm::Constant *BlockFunction::BuildbyrefDestroyHelper(const llvm::Type *T, - int flag, + int Flag, unsigned Align) { // All alignments below that of pointer alignment collpase down to just // pointer alignment, as we always have at least that much alignment to begin // with. Align /= unsigned(CGF.Target.getPointerAlign(0)/8); + // As an optimization, we only generate a single function of each kind we // might need. We need a different one for each alignment and for each // setting of flags. We mix Align and flag to get the kind. - uint64_t kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + flag; - llvm::Constant *& Entry = CGM.DestroyCache[kind]; + uint64_t Kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + Flag; + llvm::Constant *&Entry = CGM.DestroyCache[Kind]; if (Entry) return Entry; - return Entry=CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, flag); + return Entry=CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, Flag); } llvm::Value *BlockFunction::getBlockObjectDispose() { diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index be4c27c..c704432 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -204,7 +204,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall(F, ArgValue, "tmp")); } case Builtin::BI__builtin_object_size: { -#if 1 // We pass this builtin onto the optimizer so that it can // figure out the object size in more complex cases. const llvm::Type *ResType[] = { @@ -214,15 +213,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall2(F, EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)))); -#else - // FIXME: Remove after testing. - llvm::APSInt TypeArg = E->getArg(1)->EvaluateAsInt(CGM.getContext()); - const llvm::Type *ResType = ConvertType(E->getType()); - // bool UseSubObject = TypeArg.getZExtValue() & 1; - bool UseMinimum = TypeArg.getZExtValue() & 2; - return RValue::get( - llvm::ConstantInt::get(ResType, UseMinimum ? 0 : -1LL)); -#endif } case Builtin::BI__builtin_prefetch: { Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0)); @@ -815,13 +805,44 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Ops[0] = Builder.CreateBitCast(Ops[0], PtrTy); return Builder.CreateStore(Ops[1], Ops[0]); } - case X86::BI__builtin_ia32_palignr128: case X86::BI__builtin_ia32_palignr: { - Function *F = CGM.getIntrinsic(BuiltinID == X86::BI__builtin_ia32_palignr128 ? - Intrinsic::x86_ssse3_palign_r_128 : - Intrinsic::x86_ssse3_palign_r); + Function *F = CGM.getIntrinsic(Intrinsic::x86_ssse3_palign_r); return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size()); } + case X86::BI__builtin_ia32_palignr128: { + unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue(); + + // If palignr is shifting the pair of input vectors less than 17 bytes, + // emit a shuffle instruction. + if (shiftVal <= 16) { + const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext); + + llvm::SmallVector<llvm::Constant*, 16> Indices; + for (unsigned i = 0; i != 16; ++i) + Indices.push_back(llvm::ConstantInt::get(IntTy, shiftVal + i)); + + Value* SV = llvm::ConstantVector::get(Indices.begin(), Indices.size()); + return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr"); + } + + // If palignr is shifting the pair of input vectors more than 16 but less + // than 32 bytes, emit a logical right shift of the destination. + if (shiftVal < 32) { + const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext); + const llvm::Type *VecTy = llvm::VectorType::get(EltTy, 2); + const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext); + + Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast"); + Ops[1] = llvm::ConstantInt::get(IntTy, (shiftVal-16) * 8); + + // create i32 constant + llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_psrl_dq); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + 2, "palignr"); + } + + // If palignr is shifting the pair of vectors more than 32 bytes, emit zero. + return llvm::Constant::getNullValue(ConvertType(E->getType())); + } } } diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 34d1c8d..0d11be2 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -26,168 +26,6 @@ using namespace clang; using namespace CodeGen; -void -CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, - 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::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(); - bool isVolatile = getContext().getCanonicalType(T).isVolatileQualified(); - - if (T->isReferenceType()) { - ErrorUnsupported(Init, "global variable that binds to a reference"); - } else if (!hasAggregateLLVMType(T)) { - llvm::Value *V = EmitScalarExpr(Init); - EmitStoreOfScalar(V, DeclPtr, isVolatile, T); - } else if (T->isAnyComplexType()) { - EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); - } else { - EmitAggExpr(Init, DeclPtr, isVolatile); - // Avoid generating destructor(s) for initialized objects. - if (!isa<CXXConstructExpr>(Init)) - return; - const ConstantArrayType *Array = getContext().getAsConstantArrayType(T); - if (Array) - T = getContext().getBaseElementType(Array); - - if (const RecordType *RT = T->getAs<RecordType>()) { - CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (!RD->hasTrivialDestructor()) { - llvm::Constant *DtorFn; - if (Array) { - DtorFn = CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper( - RD->getDestructor(getContext()), - Array, DeclPtr); - DeclPtr = - llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext)); - } - else - DtorFn = CGM.GetAddrOfCXXDestructor(RD->getDestructor(getContext()), - Dtor_Complete); - EmitCXXGlobalDtorRegistration(DtorFn, 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 && - "thread safe statics are currently not supported!"); - - llvm::SmallString<256> GuardVName; - CGM.getMangleContext().mangleGuardVariable(&D, GuardVName); - - // Create the guard variable. - llvm::GlobalValue *GuardV = - new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), - false, GV->getLinkage(), - 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::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::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); - - EmitCXXGlobalVarDeclInit(D, GV); - - Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), - 1), - Builder.CreateBitCast(GuardV, PtrTy)); - - EmitBlock(EndBlock); -} - RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, llvm::Value *Callee, llvm::Value *This, @@ -241,10 +79,10 @@ static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) { } RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { - if (isa<BinaryOperator>(CE->getCallee())) + if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens())) return EmitCXXMemberPointerCallExpr(CE); - const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()); + const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens()); const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); if (MD->isStatic()) { @@ -307,7 +145,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { RValue CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E) { - const BinaryOperator *BO = cast<BinaryOperator>(E->getCallee()); + const BinaryOperator *BO = + cast<BinaryOperator>(E->getCallee()->IgnoreParens()); const Expr *BaseExpr = BO->getLHS(); const Expr *MemFnExpr = BO->getRHS(); @@ -519,7 +358,7 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, // C++ [class.temporary]p4: // There are two contexts in which temporaries are destroyed at a different - // point than the end of the full- expression. The first context is when a + // point than the end of the full-expression. The first context is when a // default constructor is called to initialize an element of an array. // If the constructor has one or more default arguments, the destruction of // every temporary created in a default argument expression is sequenced @@ -558,8 +397,9 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); assert(CA && "Do we support VLA for destruction ?"); uint64_t ElementCount = getContext().getConstantArrayElementCount(CA); - llvm::Value* ElementCountPtr = - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), ElementCount); + + const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType()); + llvm::Value* ElementCountPtr = llvm::ConstantInt::get(SizeLTy, ElementCount); EmitCXXAggrDestructorCall(D, ElementCountPtr, This); } @@ -569,13 +409,14 @@ void CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, llvm::Value *UpperCount, llvm::Value *This) { - llvm::Value *One = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - 1); + const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType()); + llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1); + // 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 *IndexPtr = CreateTempAlloca(SizeLTy, "loop.index"); + + // Store the number of elements in the index pointer. Builder.CreateStore(UpperCount, IndexPtr); // Start the loop with a block that tests the condition. @@ -589,7 +430,7 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, // 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::Constant::getNullValue(SizeLTy); llvm::Value *Counter = Builder.CreateLoad(IndexPtr); llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant, "isne"); @@ -626,7 +467,6 @@ llvm::Constant * CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, const ArrayType *Array, llvm::Value *This) { - static int UniqueCount; FunctionArgList Args; ImplicitParamDecl *Dst = ImplicitParamDecl::Create(getContext(), 0, @@ -635,16 +475,15 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, Args.push_back(std::make_pair(Dst, Dst->getType())); llvm::SmallString<16> Name; - llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueCount); + llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount); QualType R = getContext().VoidTy; const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false); llvm::Function *Fn = llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, - Name.c_str(), + Name.str(), &CGM.getModule()); - IdentifierInfo *II - = &CGM.getContext().Idents.get(Name.c_str()); + IdentifierInfo *II = &CGM.getContext().Idents.get(Name.str()); FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, @@ -691,21 +530,29 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, EmitCXXMemberCall(D, Callee, This, ArgBeg, ArgEnd); } -void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *D, +void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, llvm::Value *This) { - if (D->isVirtual()) { - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(D), - /*isVariadic=*/false); + llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type); + + CallArgList Args; + + // Push the this ptr. + Args.push_back(std::make_pair(RValue::get(This), + DD->getThisType(getContext()))); + + // Add a VTT parameter if necessary. + // FIXME: This should not be a dummy null parameter! + if (Type == Dtor_Base && DD->getParent()->getNumVBases() != 0) { + QualType T = getContext().getPointerType(getContext().VoidPtrTy); - llvm::Value *Callee = BuildVirtualCall(D, Dtor_Deleting, This, Ty); - EmitCXXMemberCall(D, Callee, This, 0, 0); - return; + Args.push_back(std::make_pair(RValue::get(CGM.EmitNullConstant(T)), T)); } - llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(D, Type); - EmitCXXMemberCall(D, Callee, This, 0, 0); + // FIXME: We should try to share this code with EmitCXXMemberCall. + + QualType ResultType = DD->getType()->getAs<FunctionType>()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, Args, DD); } void @@ -793,9 +640,9 @@ const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D, void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { if (D->isVirtual()) - EmitGlobalDefinition(GlobalDecl(D, Dtor_Deleting)); - EmitGlobalDefinition(GlobalDecl(D, Dtor_Complete)); - EmitGlobalDefinition(GlobalDecl(D, Dtor_Base)); + EmitGlobal(GlobalDecl(D, Dtor_Deleting)); + EmitGlobal(GlobalDecl(D, Dtor_Complete)); + EmitGlobal(GlobalDecl(D, Dtor_Base)); } void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D, @@ -829,10 +676,10 @@ const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D, } llvm::Constant * -CodeGenFunction::GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, +CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment) { - return GenerateCovariantThunk(Fn, MD, Extern, + return GenerateCovariantThunk(Fn, GD, Extern, CovariantThunkAdjustment(ThisAdjustment, ThunkAdjustment())); } @@ -875,8 +722,9 @@ CodeGenFunction::DynamicTypeAdjust(llvm::Value *V, llvm::Constant * CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, - const CXXMethodDecl *MD, bool Extern, + GlobalDecl GD, bool Extern, const CovariantThunkAdjustment &Adjustment) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); FunctionArgList Args; @@ -906,7 +754,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, const llvm::Type *Ty = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), FPT->isVariadic()); - llvm::Value *Callee = CGM.GetAddrOfFunction(MD, Ty); + llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty); + CallArgList CallArgs; bool ShouldAdjustReturnPointer = true; @@ -922,7 +771,7 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, CovariantThunkAdjustment(ThunkAdjustment(), Adjustment.ReturnAdjustment); - Callee = CGM.BuildCovariantThunk(MD, Extern, ReturnAdjustment); + Callee = CGM.BuildCovariantThunk(GD, Extern, ReturnAdjustment); Callee = Builder.CreateBitCast(Callee, OrigTy); ShouldAdjustReturnPointer = false; @@ -938,7 +787,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, QualType ArgType = D->getType(); // llvm::Value *Arg = CGF.GetAddrOfLocalVar(Dst); - Expr *Arg = new (getContext()) DeclRefExpr(D, ArgType, SourceLocation()); + Expr *Arg = new (getContext()) DeclRefExpr(D, ArgType.getNonReferenceType(), + SourceLocation()); CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType)); } @@ -983,11 +833,117 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, } llvm::Constant * -CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, +CodeGenModule::GetAddrOfThunk(GlobalDecl GD, + const ThunkAdjustment &ThisAdjustment) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + // Compute mangled name + llvm::SmallString<256> OutName; + if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD)) + getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), ThisAdjustment, + OutName); + else + getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); + OutName += '\0'; + const char* Name = UniqueMangledName(OutName.begin(), OutName.end()); + + // Get function for mangled name + const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); +} + +llvm::Constant * +CodeGenModule::GetAddrOfCovariantThunk(GlobalDecl GD, + const CovariantThunkAdjustment &Adjustment) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + // Compute mangled name + llvm::SmallString<256> OutName; + getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName); + OutName += '\0'; + const char* Name = UniqueMangledName(OutName.begin(), OutName.end()); + + // Get function for mangled name + const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); +} + +void CodeGenModule::BuildThunksForVirtual(GlobalDecl GD) { + CGVtableInfo::AdjustmentVectorTy *AdjPtr = getVtableInfo().getAdjustments(GD); + if (!AdjPtr) + return; + CGVtableInfo::AdjustmentVectorTy &Adj = *AdjPtr; + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + for (unsigned i = 0; i < Adj.size(); i++) { + GlobalDecl OGD = Adj[i].first; + const CXXMethodDecl *OMD = cast<CXXMethodDecl>(OGD.getDecl()); + QualType nc_oret = OMD->getType()->getAs<FunctionType>()->getResultType(); + CanQualType oret = getContext().getCanonicalType(nc_oret); + QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType(); + CanQualType ret = getContext().getCanonicalType(nc_ret); + ThunkAdjustment ReturnAdjustment; + if (oret != ret) { + QualType qD = nc_ret->getPointeeType(); + QualType qB = nc_oret->getPointeeType(); + CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); + CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); + ReturnAdjustment = ComputeThunkAdjustment(D, B); + } + ThunkAdjustment ThisAdjustment = Adj[i].second; + bool Extern = !cast<CXXRecordDecl>(OMD->getDeclContext())->isInAnonymousNamespace(); + if (!ReturnAdjustment.isEmpty() || !ThisAdjustment.isEmpty()) { + CovariantThunkAdjustment CoAdj(ThisAdjustment, ReturnAdjustment); + llvm::Constant *FnConst; + if (!ReturnAdjustment.isEmpty()) + FnConst = GetAddrOfCovariantThunk(GD, CoAdj); + else + FnConst = GetAddrOfThunk(GD, ThisAdjustment); + if (!isa<llvm::Function>(FnConst)) { + llvm::Constant *SubExpr = + cast<llvm::ConstantExpr>(FnConst)->getOperand(0); + llvm::Function *OldFn = cast<llvm::Function>(SubExpr); + std::string Name = OldFn->getNameStr(); + GlobalDeclMap.erase(UniqueMangledName(Name.data(), + Name.data() + Name.size() + 1)); + llvm::Constant *NewFnConst; + if (!ReturnAdjustment.isEmpty()) + NewFnConst = GetAddrOfCovariantThunk(GD, CoAdj); + else + NewFnConst = GetAddrOfThunk(GD, ThisAdjustment); + llvm::Function *NewFn = cast<llvm::Function>(NewFnConst); + NewFn->takeName(OldFn); + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(NewFn, OldFn->getType()); + OldFn->replaceAllUsesWith(NewPtrForOldDecl); + OldFn->eraseFromParent(); + FnConst = NewFn; + } + llvm::Function *Fn = cast<llvm::Function>(FnConst); + if (Fn->isDeclaration()) { + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::WeakAnyLinkage; + if (!Extern) + linktype = llvm::GlobalValue::InternalLinkage; + Fn->setLinkage(linktype); + if (!Features.Exceptions && !Features.ObjCNonFragileABI) + Fn->addFnAttr(llvm::Attribute::NoUnwind); + Fn->setAlignment(2); + CodeGenFunction(*this).GenerateCovariantThunk(Fn, GD, Extern, CoAdj); + } + } + } +} + +llvm::Constant * +CodeGenModule::BuildThunk(GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment) { - + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); llvm::SmallString<256> OutName; - getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); + if (const CXXDestructorDecl *D = dyn_cast<CXXDestructorDecl>(MD)) { + getMangleContext().mangleCXXDtorThunk(D, GD.getDtorType(), ThisAdjustment, + OutName); + } else + getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::WeakAnyLinkage; @@ -1001,14 +957,15 @@ CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(), &getModule()); - CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, ThisAdjustment); + CodeGenFunction(*this).GenerateThunk(Fn, GD, Extern, ThisAdjustment); llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); return m; } llvm::Constant * -CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern, +CodeGenModule::BuildCovariantThunk(const GlobalDecl &GD, bool Extern, const CovariantThunkAdjustment &Adjustment) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); llvm::SmallString<256> OutName; getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName); llvm::GlobalVariable::LinkageTypes linktype; @@ -1453,6 +1410,8 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); } } + + InitializeVtablePtrs(ClassDecl); FinishFunction(); } @@ -1537,8 +1496,16 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, // 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); + if (!hasAggregateLLVMType(Field->getType())) { + RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); + EmitStoreThroughLValue(RVRHS, LHS, Field->getType()); + } else if (Field->getType()->isAnyComplexType()) { + ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(), + RHS.isVolatileQualified()); + StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified()); + } else { + EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); + } } // return *this; @@ -1666,8 +1633,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, const CXXRecordDecl *ClassDecl = CD->getParent(); // FIXME: Add vbase initialization - llvm::Value *LoadOfThis = 0; - + for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(), E = CD->init_end(); B != E; ++B) { @@ -1686,18 +1652,28 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, PopCXXTemporary(); } - // 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 = CGM.getVtableInfo().getVtable(ClassDecl); - Builder.CreateStore(vtable, VtableField); - } + InitializeVtablePtrs(ClassDecl); +} + +void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) { + if (!ClassDecl->isDynamicClass()) + return; + + // Initialize the vtable pointer. + // FIXME: This needs to initialize secondary vtable pointers too. + llvm::Value *ThisPtr = LoadCXXThis(); + + llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl); + uint64_t AddressPoint = CGM.getVtableInfo().getVtableAddressPoint(ClassDecl); + + llvm::Value *VtableAddressPoint = + Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint); + + llvm::Value *VtableField = + Builder.CreateBitCast(ThisPtr, + VtableAddressPoint->getType()->getPointerTo()); + + Builder.CreateStore(VtableAddressPoint, VtableField); } /// EmitDtorEpilogue - Emit all code that comes at the end of class's @@ -1808,9 +1784,12 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, } // If we have a deleting destructor, emit a call to the delete operator. - if (DtorType == Dtor_Deleting) + if (DtorType == Dtor_Deleting) { + assert(DD->getOperatorDelete() && + "operator delete missing - EmitDtorEpilogue"); EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(), getContext().getTagDeclType(ClassDecl)); + } } void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index decc73c..4856f54 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -561,6 +561,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const ABIArgInfo &AI = it->info; unsigned Attributes = 0; + if (ParamType.isRestrictQualified()) + Attributes |= llvm::Attribute::NoAlias; + switch (AI.getKind()) { case ABIArgInfo::Coerce: break; @@ -764,7 +767,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, ComplexPairTy RT = LoadComplexFromAddr(ReturnValue, false); StoreComplexToAddr(RT, CurFn->arg_begin(), false); } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - EmitAggregateCopy(CurFn->arg_begin(), ReturnValue, RetTy); + // Do nothing; aggregrates get evaluated directly into the destination. } else { EmitStoreOfScalar(Builder.CreateLoad(ReturnValue), CurFn->arg_begin(), false, RetTy); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index b3c2b98..fd2afe7 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -112,6 +112,42 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF, return NonVirtualOffset; } +// FIXME: This probably belongs in CGVtable, but it relies on +// the static function ComputeNonVirtualBaseClassOffset, so we should make that +// a CodeGenModule member function as well. +ThunkAdjustment +CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl) { + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + if (!const_cast<CXXRecordDecl *>(ClassDecl)-> + isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return ThunkAdjustment(); + } + + unsigned Start = 0; + uint64_t VirtualOffset = 0; + + const CXXBasePath &Path = Paths.front(); + const CXXRecordDecl *VBase = 0; + for (unsigned i = 0, e = Path.size(); i != e; ++i) { + const CXXBasePathElement& Element = Path[i]; + if (Element.Base->isVirtual()) { + Start = i+1; + QualType VBaseType = Element.Base->getType(); + VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl()); + } + } + if (VBase) + VirtualOffset = + getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl); + + uint64_t Offset = + ComputeNonVirtualBaseClassOffset(getContext(), Paths, Start); + return ThunkAdjustment(Offset, VirtualOffset); +} + llvm::Value * CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, const CXXRecordDecl *ClassDecl, diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 317da7e..2238c89 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -35,8 +35,8 @@ using namespace clang; using namespace clang::CodeGen; -CGDebugInfo::CGDebugInfo(CodeGenModule *m) - : M(m), isMainCompileUnitCreated(false), DebugFactory(M->getModule()), +CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) + : CGM(CGM), isMainCompileUnitCreated(false), DebugFactory(CGM.getModule()), BlockLiteralGenericSet(false) { } @@ -46,7 +46,7 @@ CGDebugInfo::~CGDebugInfo() { void CGDebugInfo::setLocation(SourceLocation Loc) { if (Loc.isValid()) - CurLoc = M->getContext().getSourceManager().getInstantiationLoc(Loc); + CurLoc = CGM.getContext().getSourceManager().getInstantiationLoc(Loc); } /// getContext - Get context info for the decl. @@ -70,7 +70,7 @@ llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl, llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { // Get source file information. const char *FileName = "<unknown>"; - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); unsigned FID = 0; if (Loc.isValid()) { PresumedLoc PLoc = SM.getPresumedLoc(Loc); @@ -84,18 +84,14 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { // Get absolute path name. llvm::sys::Path AbsFileName(FileName); - if (!AbsFileName.isAbsolute()) { - llvm::sys::Path tmp = llvm::sys::Path::GetCurrentDirectory(); - tmp.appendComponent(FileName); - AbsFileName = tmp; - } + AbsFileName.makeAbsolute(); // See if thie compile unit is representing main source file. Each source // file has corresponding compile unit. There is only one main source // file at a time. bool isMain = false; - const LangOptions &LO = M->getLangOptions(); - const CodeGenOptions &CGO = M->getCodeGenOpts(); + const LangOptions &LO = CGM.getLangOptions(); + const CodeGenOptions &CGO = CGM.getCodeGenOpts(); if (isMainCompileUnitCreated == false) { if (!CGO.MainFileName.empty()) { if (AbsFileName.getLast() == CGO.MainFileName) @@ -122,7 +118,7 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { LangTag = llvm::dwarf::DW_LANG_C89; } - std::string Producer = + const char *Producer = #ifdef CLANG_VENDOR CLANG_VENDOR #endif @@ -137,9 +133,9 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { // Create new compile unit. return Unit = DebugFactory.CreateCompileUnit(LangTag, - AbsFileName.getLast().c_str(), - AbsFileName.getDirname().c_str(), - Producer.c_str(), isMain, + AbsFileName.getLast(), + AbsFileName.getDirname(), + Producer, isMain, isOptimized, Flags, RuntimeVers); } @@ -170,13 +166,13 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT, case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break; } // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(BT); - uint64_t Align = M->getContext().getTypeAlign(BT); + uint64_t Size = CGM.getContext().getTypeSize(BT); + uint64_t Align = CGM.getContext().getTypeAlign(BT); uint64_t Offset = 0; llvm::DIType DbgTy = DebugFactory.CreateBasicType(Unit, - BT->getName(M->getContext().getLangOptions()), + BT->getName(CGM.getContext().getLangOptions()), Unit, 0, Size, Align, Offset, /*flags*/ 0, Encoding); return DbgTy; @@ -189,8 +185,8 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty, if (Ty->isComplexIntegerType()) Encoding = llvm::dwarf::DW_ATE_lo_user; - uint64_t Size = M->getContext().getTypeSize(Ty); - uint64_t Align = M->getContext().getTypeAlign(Ty); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); uint64_t Offset = 0; llvm::DIType DbgTy = @@ -262,8 +258,8 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag, // Size is always the size of a pointer. We can't use getTypeSize here // because that does not return the correct value for references. uint64_t Size = - M->getContext().Target.getPointerWidth(PointeeTy.getAddressSpace()); - uint64_t Align = M->getContext().getTypeAlign(Ty); + CGM.getContext().Target.getPointerWidth(PointeeTy.getAddressSpace()); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); return DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(), @@ -291,10 +287,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, llvm::DIType EltTy, DescTy; FieldOffset = 0; - FType = M->getContext().UnsignedLongTy; + FType = CGM.getContext().UnsignedLongTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "reserved", DefUnit, 0, FieldSize, FieldAlign, @@ -302,10 +298,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().UnsignedLongTy; + FType = CGM.getContext().UnsignedLongTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "Size", DefUnit, 0, FieldSize, FieldAlign, @@ -323,18 +319,18 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, llvm::DIType(), Elements); // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(Ty); - uint64_t Align = M->getContext().getTypeAlign(Ty); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); DescTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, "", llvm::DICompileUnit(), 0, Size, Align, 0, 0, EltTy); FieldOffset = 0; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__isa", DefUnit, 0, FieldSize, FieldAlign, @@ -342,10 +338,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().IntTy; + FType = CGM.getContext().IntTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__flags", DefUnit, 0, FieldSize, FieldAlign, @@ -353,10 +349,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().IntTy; + FType = CGM.getContext().IntTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__reserved", DefUnit, 0, FieldSize, FieldAlign, @@ -364,10 +360,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__FuncPtr", DefUnit, 0, FieldSize, FieldAlign, @@ -375,10 +371,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = DescTy; - FieldSize = M->getContext().getTypeSize(Ty); - FieldAlign = M->getContext().getTypeAlign(Ty); + FieldSize = CGM.getContext().getTypeSize(Ty); + FieldAlign = CGM.getContext().getTypeAlign(Ty); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__descriptor", DefUnit, 0, FieldSize, FieldAlign, @@ -411,7 +407,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, SourceLocation DefLoc = Ty->getDecl()->getLocation(); llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(DefLoc); unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); @@ -464,7 +460,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, Tag = llvm::dwarf::DW_TAG_class_type; } - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); // Get overall information about the record type for the debug info. PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); @@ -487,7 +483,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, llvm::DIType(), llvm::DIArray()); // If this is just a forward declaration, return it. - if (!Decl->getDefinition(M->getContext())) + if (!Decl->getDefinition(CGM.getContext())) return FwdDecl; llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode(); @@ -498,7 +494,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, // Convert all the elements. llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; - const ASTRecordLayout &RL = M->getContext().getASTRecordLayout(Decl); + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(Decl); unsigned FieldNo = 0; for (RecordDecl::field_iterator I = Decl->field_begin(), @@ -530,12 +526,12 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, if (!FType->isIncompleteArrayType()) { // Bit size, align and offset of the type. - FieldSize = M->getContext().getTypeSize(FType); + FieldSize = CGM.getContext().getTypeSize(FType); Expr *BitWidth = Field->getBitWidth(); if (BitWidth) - FieldSize = BitWidth->EvaluateAsInt(M->getContext()).getZExtValue(); + FieldSize = BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue(); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); } uint64_t FieldOffset = RL.getFieldOffset(FieldNo); @@ -554,8 +550,8 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(Ty); - uint64_t Align = M->getContext().getTypeAlign(Ty); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); llvm::DICompositeType RealDecl = DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), @@ -575,7 +571,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, ObjCInterfaceDecl *Decl = Ty->getDecl(); unsigned Tag = llvm::dwarf::DW_TAG_structure_type; - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); // Get overall information about the record type for the debug info. llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(Decl->getLocation()); @@ -612,7 +608,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, ObjCInterfaceDecl *SClass = Decl->getSuperClass(); if (SClass) { llvm::DIType SClassTy = - getOrCreateType(M->getContext().getObjCInterfaceType(SClass), Unit); + getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit); llvm::DIType InhTag = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_inheritance, Unit, "", llvm::DICompileUnit(), 0, 0, 0, @@ -620,7 +616,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, EltTys.push_back(InhTag); } - const ASTRecordLayout &RL = M->getContext().getASTObjCInterfaceLayout(Decl); + const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(Decl); unsigned FieldNo = 0; for (ObjCInterfaceDecl::ivar_iterator I = Decl->ivar_begin(), @@ -648,12 +644,12 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, if (!FType->isIncompleteArrayType()) { // Bit size, align and offset of the type. - FieldSize = M->getContext().getTypeSize(FType); + FieldSize = CGM.getContext().getTypeSize(FType); Expr *BitWidth = Field->getBitWidth(); if (BitWidth) - FieldSize = BitWidth->EvaluateAsInt(M->getContext()).getZExtValue(); + FieldSize = BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue(); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); } uint64_t FieldOffset = RL.getFieldOffset(FieldNo); @@ -678,8 +674,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(Ty); - uint64_t Align = M->getContext().getTypeAlign(Ty); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); llvm::DICompositeType RealDecl = DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), DefUnit, @@ -713,7 +709,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, SourceLocation DefLoc = Decl->getLocation(); llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(DefLoc); unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); @@ -722,8 +718,8 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, uint64_t Size = 0; unsigned Align = 0; if (!Ty->isIncompleteType()) { - Size = M->getContext().getTypeSize(Ty); - Align = M->getContext().getTypeAlign(Ty); + Size = CGM.getContext().getTypeSize(Ty); + Align = CGM.getContext().getTypeAlign(Ty); } llvm::DIType DbgTy = @@ -754,14 +750,14 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(Ty)) { Size = 0; Align = - M->getContext().getTypeAlign(M->getContext().getBaseElementType(VAT)); + CGM.getContext().getTypeAlign(CGM.getContext().getBaseElementType(VAT)); } else if (Ty->isIncompleteArrayType()) { Size = 0; - Align = M->getContext().getTypeAlign(Ty->getElementType()); + Align = CGM.getContext().getTypeAlign(Ty->getElementType()); } else { // Size and align of the whole array, not the element type. - Size = M->getContext().getTypeSize(Ty); - Align = M->getContext().getTypeAlign(Ty); + Size = CGM.getContext().getTypeSize(Ty); + Align = CGM.getContext().getTypeAlign(Ty); } // Add the dimensions of the array. FIXME: This loses CV qualifiers from @@ -797,6 +793,47 @@ llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty, Ty, Ty->getPointeeType(), Unit); } +llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty, + llvm::DICompileUnit U) { + QualType PointerDiffTy = CGM.getContext().getPointerDiffType(); + llvm::DIType PointerDiffDITy = getOrCreateType(PointerDiffTy, U); + + if (!Ty->getPointeeType()->isFunctionType()) { + // We have a data member pointer type. + return PointerDiffDITy; + } + + // We have a member function pointer type. Treat it as a struct with two + // ptrdiff_t members. + std::pair<uint64_t, unsigned> Info = CGM.getContext().getTypeInfo(Ty); + + uint64_t FieldOffset = 0; + llvm::DIDescriptor ElementTypes[2]; + + // FIXME: This should probably be a function type instead. + ElementTypes[0] = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, U, + "ptr", llvm::DICompileUnit(), 0, + Info.first, Info.second, FieldOffset, 0, + PointerDiffDITy); + FieldOffset += Info.first; + + ElementTypes[1] = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, U, + "ptr", llvm::DICompileUnit(), 0, + Info.first, Info.second, FieldOffset, 0, + PointerDiffDITy); + + llvm::DIArray Elements = + DebugFactory.GetOrCreateArray(&ElementTypes[0], + llvm::array_lengthof(ElementTypes)); + + return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_structure_type, + U, llvm::StringRef("test"), + llvm::DICompileUnit(), 0, FieldOffset, + 0, 0, 0, llvm::DIType(), Elements); +} + static QualType CanonicalizeTypeForDebugInfo(QualType T) { switch (T->getTypeClass()) { default: @@ -895,25 +932,27 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::LValueReference: return CreateType(cast<LValueReferenceType>(Ty), Unit); + case Type::MemberPointer: + return CreateType(cast<MemberPointerType>(Ty), Unit); } } /// EmitFunctionStart - Constructs the debug code for entering a function - /// "llvm.dbg.func.start.". -void CGDebugInfo::EmitFunctionStart(const char *Name, QualType FnType, +void CGDebugInfo::EmitFunctionStart(llvm::StringRef Name, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder) { - const char *LinkageName = Name; + llvm::StringRef LinkageName(Name); // Skip the asm prefix if it exists. // // FIXME: This should probably be the unmangled name? if (Name[0] == '\01') - ++Name; + Name = Name.substr(1); // FIXME: Why is this using CurLoc??? llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); unsigned LineNo = SM.getPresumedLoc(CurLoc).getLine(); llvm::DISubprogram SP = @@ -930,7 +969,7 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) { if (CurLoc.isInvalid() || CurLoc.isMacroID()) return; // Don't bother if things are the same as last time. - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); if (CurLoc == PrevLoc || (SM.getInstantiationLineNumber(CurLoc) == SM.getInstantiationLineNumber(PrevLoc) @@ -982,7 +1021,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, // Do not emit variable debug information while generating optimized code. // The llvm optimizer and code generator are not yet ready to support // optimized code debugging. - const CodeGenOptions &CGO = M->getCodeGenOpts(); + const CodeGenOptions &CGO = CGM.getCodeGenOpts(); if (CGO.OptimizationLevel) return; @@ -1006,10 +1045,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, // Build up structure for the byref. See BuildByRefType. FieldOffset = 0; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__isa", DefUnit, 0, FieldSize, FieldAlign, @@ -1017,10 +1056,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__forwarding", DefUnit, 0, FieldSize, FieldAlign, @@ -1028,10 +1067,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__flags", DefUnit, 0, FieldSize, FieldAlign, @@ -1039,10 +1078,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__size", DefUnit, 0, FieldSize, FieldAlign, @@ -1050,12 +1089,12 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - bool HasCopyAndDispose = M->BlockRequiresCopying(Type); + bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type); if (HasCopyAndDispose) { - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__copy_helper", DefUnit, 0, FieldSize, FieldAlign, @@ -1063,10 +1102,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__destroy_helper", DefUnit, 0, FieldSize, FieldAlign, @@ -1075,8 +1114,8 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, FieldOffset += FieldSize; } - unsigned Align = M->getContext().getDeclAlignInBytes(Decl); - if (Align > M->getContext().Target.getPointerAlign(0) / 8) { + unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl); + if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) { unsigned AlignedOffsetInBytes = llvm::RoundUpToAlignment(FieldOffset/8, Align); unsigned NumPaddingBytes @@ -1084,11 +1123,11 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, if (NumPaddingBytes > 0) { llvm::APInt pad(32, NumPaddingBytes); - FType = M->getContext().getConstantArrayType(M->getContext().CharTy, + FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, pad, ArrayType::Normal, 0); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "", DefUnit, 0, FieldSize, FieldAlign, @@ -1100,7 +1139,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, FType = Type; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); + FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = Align*8; FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, @@ -1121,7 +1160,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, } // Get location information. - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned Line = 0; unsigned Column = 0; @@ -1158,7 +1197,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, // Do not emit variable debug information while generating optimized code. // The llvm optimizer and code generator are not yet ready to support // optimized code debugging. - const CodeGenOptions &CGO = M->getCodeGenOpts(); + const CodeGenOptions &CGO = CGM.getCodeGenOpts(); if (CGO.OptimizationLevel || Builder.GetInsertBlock() == 0) return; @@ -1183,10 +1222,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, // Build up structure for the byref. See BuildByRefType. FieldOffset = 0; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__isa", DefUnit, 0, FieldSize, FieldAlign, @@ -1194,10 +1233,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__forwarding", DefUnit, 0, FieldSize, FieldAlign, @@ -1205,10 +1244,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__flags", DefUnit, 0, FieldSize, FieldAlign, @@ -1216,10 +1255,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__size", DefUnit, 0, FieldSize, FieldAlign, @@ -1227,12 +1266,12 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - bool HasCopyAndDispose = M->BlockRequiresCopying(Type); + bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type); if (HasCopyAndDispose) { - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__copy_helper", DefUnit, 0, FieldSize, FieldAlign, @@ -1240,10 +1279,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__destroy_helper", DefUnit, 0, FieldSize, FieldAlign, @@ -1252,8 +1291,8 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, FieldOffset += FieldSize; } - unsigned Align = M->getContext().getDeclAlignInBytes(Decl); - if (Align > M->getContext().Target.getPointerAlign(0) / 8) { + unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl); + if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) { unsigned AlignedOffsetInBytes = llvm::RoundUpToAlignment(FieldOffset/8, Align); unsigned NumPaddingBytes @@ -1261,11 +1300,11 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, if (NumPaddingBytes > 0) { llvm::APInt pad(32, NumPaddingBytes); - FType = M->getContext().getConstantArrayType(M->getContext().CharTy, + FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, pad, ArrayType::Normal, 0); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "", DefUnit, 0, FieldSize, FieldAlign, @@ -1277,7 +1316,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, FType = Type; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); + FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = Align*8; XOffset = FieldOffset; @@ -1299,7 +1338,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, } // Get location information. - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned Line = 0; if (!PLoc.isInvalid()) @@ -1309,7 +1348,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, uint64_t offset = CGF->BlockDecls[Decl]; llvm::SmallVector<llvm::Value *, 9> addr; - llvm::LLVMContext &VMContext = M->getLLVMContext(); + llvm::LLVMContext &VMContext = CGM.getLLVMContext(); addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), llvm::DIFactory::OpDeref)); addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), @@ -1376,7 +1415,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, // Create global variable debug descriptor. llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); @@ -1387,9 +1426,9 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, llvm::APSInt ConstVal(32); ConstVal = 1; - QualType ET = M->getContext().getAsArrayType(T)->getElementType(); + QualType ET = CGM.getContext().getAsArrayType(T)->getElementType(); - T = M->getContext().getConstantArrayType(ET, ConstVal, + T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } llvm::StringRef DeclName = Decl->getName(); @@ -1405,22 +1444,22 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, ObjCInterfaceDecl *Decl) { // Create global variable debug descriptor. llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); llvm::StringRef Name = Decl->getName(); - QualType T = M->getContext().getObjCInterfaceType(Decl); + QualType T = CGM.getContext().getObjCInterfaceType(Decl); if (T->isIncompleteArrayType()) { // CodeGen turns int[] into int[1] so we'll do the same here. llvm::APSInt ConstVal(32); ConstVal = 1; - QualType ET = M->getContext().getAsArrayType(T)->getElementType(); + QualType ET = CGM.getContext().getAsArrayType(T)->getElementType(); - T = M->getContext().getConstantArrayType(ET, ConstVal, + T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index af86e2b..7df2a62 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -40,7 +40,7 @@ namespace CodeGen { /// and is responsible for emitting to llvm globals or pass directly to /// the backend. class CGDebugInfo { - CodeGenModule *M; + CodeGenModule &CGM; bool isMainCompileUnitCreated; llvm::DIFactory DebugFactory; @@ -74,12 +74,13 @@ class CGDebugInfo { llvm::DIType CreateType(const EnumType *Ty, llvm::DICompileUnit U); 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); + llvm::DIType CreatePointerLikeType(unsigned Tag, const Type *Ty, QualType PointeeTy, llvm::DICompileUnit U); public: - CGDebugInfo(CodeGenModule *m); + CGDebugInfo(CodeGenModule &CGM); ~CGDebugInfo(); /// setLocation - Update the current source location. If \arg loc is @@ -92,7 +93,7 @@ public: /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate /// start of a new function. - void EmitFunctionStart(const char *Name, QualType FnType, + void EmitFunctionStart(llvm::StringRef Name, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder); /// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index c047283..14ee90d 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -43,6 +43,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Using: // using X; [C++] case Decl::UsingShadow: case Decl::UsingDirective: // using namespace X; [C++] + case Decl::StaticAssert: // static_assert(X, ""); [C++0x] // None of these decls require codegen support. return; @@ -85,28 +86,32 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) { assert(0 && "Unknown storage class"); } +static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D, + const char *Separator) { + CodeGenModule &CGM = CGF.CGM; + if (CGF.getContext().getLangOptions().CPlusPlus) + return CGM.getMangledName(&D); + + std::string ContextName; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl)) + ContextName = CGM.getMangledName(FD); + else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl)) + ContextName = CGF.CurFn->getName(); + else + // FIXME: What about in a block?? + assert(0 && "Unknown context for block var decl"); + + return ContextName + Separator + D.getNameAsString(); +} + llvm::GlobalVariable * CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D, const char *Separator, - llvm::GlobalValue::LinkageTypes - Linkage) { + llvm::GlobalValue::LinkageTypes Linkage) { QualType Ty = D.getType(); assert(Ty->isConstantSizeType() && "VLAs can't be static"); - std::string Name; - if (getContext().getLangOptions().CPlusPlus) { - Name = CGM.getMangledName(&D); - } else { - std::string ContextName; - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurFuncDecl)) - ContextName = CGM.getMangledName(FD); - else if (isa<ObjCMethodDecl>(CurFuncDecl)) - ContextName = CurFn->getName(); - else - assert(0 && "Unknown context for block var decl"); - - Name = ContextName + Separator + D.getNameAsString(); - } + std::string Name = GetStaticDeclName(*this, D, Separator); const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty); llvm::GlobalVariable *GV = @@ -118,6 +123,54 @@ CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D, return GV; } +/// AddInitializerToGlobalBlockVarDecl - Add the initializer for 'D' to the +/// global variable that has already been created for it. If the initializer +/// has a different type than GV does, this may free GV and return a different +/// one. Otherwise it just returns GV. +llvm::GlobalVariable * +CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D, + llvm::GlobalVariable *GV) { + llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this); + + // If constant emission failed, then this should be a C++ static + // initializer. + if (!Init) { + if (!getContext().getLangOptions().CPlusPlus) + CGM.ErrorUnsupported(D.getInit(), "constant l-value expression"); + else + EmitStaticCXXBlockVarDeclInit(D, GV); + return GV; + } + + // The initializer may differ in type from the global. Rewrite + // the global to match the initializer. (We have to do this + // because some types, like unions, can't be completely represented + // in the LLVM type system.) + if (GV->getType() != Init->getType()) { + llvm::GlobalVariable *OldGV = GV; + + GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), + OldGV->isConstant(), + OldGV->getLinkage(), Init, "", + 0, D.isThreadSpecified(), + D.getType().getAddressSpace()); + + // Steal the name of the old global + GV->takeName(OldGV); + + // Replace all uses of the old global with the new global + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); + OldGV->replaceAllUsesWith(NewPtrForOldDecl); + + // Erase the old global, since it is no longer used. + OldGV->eraseFromParent(); + } + + GV->setInitializer(Init); + return GV; +} + void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { llvm::Value *&DMEntry = LocalDeclMap[&D]; assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); @@ -135,45 +188,9 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { if (D.getType()->isVariablyModifiedType()) EmitVLASize(D.getType()); - if (D.getInit()) { - llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this); - - // If constant emission failed, then this should be a C++ static - // initializer. - if (!Init) { - if (!getContext().getLangOptions().CPlusPlus) - CGM.ErrorUnsupported(D.getInit(), "constant l-value expression"); - else - EmitStaticCXXBlockVarDeclInit(D, GV); - } else { - // The initializer may differ in type from the global. Rewrite - // the global to match the initializer. (We have to do this - // because some types, like unions, can't be completely represented - // in the LLVM type system.) - if (GV->getType() != Init->getType()) { - llvm::GlobalVariable *OldGV = GV; - - GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), - OldGV->isConstant(), - OldGV->getLinkage(), Init, "", - 0, D.isThreadSpecified(), - D.getType().getAddressSpace()); - - // Steal the name of the old global - GV->takeName(OldGV); - - // Replace all uses of the old global with the new global - llvm::Constant *NewPtrForOldDecl = - llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); - OldGV->replaceAllUsesWith(NewPtrForOldDecl); - - // Erase the old global, since it is no longer used. - OldGV->eraseFromParent(); - } - - GV->setInitializer(Init); - } - } + // If this value has an initializer, emit it. + if (D.getInit()) + GV = AddInitializerToGlobalBlockVarDecl(D, GV); // FIXME: Merge attribute handling. if (const AnnotateAttr *AA = D.getAttr<AnnotateAttr>()) { @@ -317,32 +334,36 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { bool isByRef = D.hasAttr<BlocksAttr>(); bool needsDispose = false; unsigned Align = 0; + bool IsSimpleConstantInitializer = false; llvm::Value *DeclPtr; if (Ty->isConstantSizeType()) { if (!Target.useGlobalsForAutomaticVariables()) { - // All constant structs and arrays should be global if - // their initializer is constant and if the element type is POD. - if (CGM.getCodeGenOpts().MergeAllConstants) { - if (Ty.isConstant(getContext()) - && (Ty->isArrayType() || Ty->isRecordType()) - && (D.getInit() - && D.getInit()->isConstantInitializer(getContext())) - && Ty->isPODType()) { + // If this value is an array or struct, is POD, and if the initializer is + // a staticly determinable constant, try to optimize it. + if (D.getInit() && !isByRef && + (Ty->isArrayType() || Ty->isRecordType()) && + Ty->isPODType() && + D.getInit()->isConstantInitializer(getContext())) { + // If this variable is marked 'const', emit the value as a global. + if (CGM.getCodeGenOpts().MergeAllConstants && + Ty.isConstant(getContext())) { EmitStaticBlockVarDecl(D); return; } + + IsSimpleConstantInitializer = true; } // A normal fixed sized variable becomes an alloca in the entry block. const llvm::Type *LTy = ConvertTypeForMem(Ty); - Align = getContext().getDeclAlignInBytes(&D); if (isByRef) LTy = BuildByRefType(&D); llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); - Alloc->setName(D.getNameAsString().c_str()); + Alloc->setName(D.getNameAsString()); + Align = getContext().getDeclAlignInBytes(&D); if (isByRef) Align = std::max(Align, unsigned(Target.getPointerAlign(0) / 8)); Alloc->setAlignment(Align); @@ -436,9 +457,48 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), D.getNameAsString()); - bool isVolatile = (getContext().getCanonicalType(D.getType()) - .isVolatileQualified()); - if (Ty->isReferenceType()) { + bool isVolatile = + getContext().getCanonicalType(D.getType()).isVolatileQualified(); + + // If the initializer was a simple constant initializer, we can optimize it + // in various ways. + if (IsSimpleConstantInitializer) { + llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(),D.getType(),this); + assert(Init != 0 && "Wasn't a simple constant init?"); + + llvm::Value *AlignVal = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Align); + const llvm::Type *IntPtr = + llvm::IntegerType::get(VMContext, LLVMPointerWidth); + llvm::Value *SizeVal = + llvm::ConstantInt::get(IntPtr, getContext().getTypeSizeInBytes(Ty)); + + const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); + if (Loc->getType() != BP) + Loc = Builder.CreateBitCast(Loc, BP, "tmp"); + + // If the initializer is all zeros, codegen with memset. + if (isa<llvm::ConstantAggregateZero>(Init)) { + llvm::Value *Zero = + llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 0); + Builder.CreateCall4(CGM.getMemSetFn(), Loc, Zero, SizeVal, AlignVal); + } else { + // Otherwise, create a temporary global with the initializer then + // memcpy from the global to the alloca. + std::string Name = GetStaticDeclName(*this, D, "."); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true, + llvm::GlobalValue::InternalLinkage, + Init, Name, 0, false, 0); + GV->setAlignment(Align); + + llvm::Value *SrcPtr = GV; + if (SrcPtr->getType() != BP) + SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp"); + + Builder.CreateCall4(CGM.getMemCpyFn(), Loc, SrcPtr, SizeVal, AlignVal); + } + } else if (Ty->isReferenceType()) { RValue RV = EmitReferenceBindingToExpr(Init, Ty, /*IsInitializer=*/true); EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty); } else if (!hasAggregateLLVMType(Init->getType())) { @@ -521,19 +581,39 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { if (const ConstantArrayType *Array = getContext().getAsConstantArrayType(Ty)) { - DelayedCleanupBlock Scope(*this); - QualType BaseElementTy = getContext().getBaseElementType(Array); - const llvm::Type *BasePtr = ConvertType(BaseElementTy); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(DeclPtr, BasePtr); - EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); + { + DelayedCleanupBlock Scope(*this); + QualType BaseElementTy = getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(DeclPtr, BasePtr); + EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); - // Make sure to jump to the exit block. - EmitBranch(Scope.getCleanupExitBlock()); + // Make sure to jump to the exit block. + EmitBranch(Scope.getCleanupExitBlock()); + } + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + QualType BaseElementTy = getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(DeclPtr, BasePtr); + EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); + } } else { - DelayedCleanupBlock Scope(*this); - EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + { + DelayedCleanupBlock Scope(*this); + EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + + // Make sure to jump to the exit block. + EmitBranch(Scope.getCleanupExitBlock()); + } + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + } } } } @@ -545,8 +625,6 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { llvm::Constant* F = CGM.GetAddrOfFunction(FD); assert(F && "Could not find function!"); - DelayedCleanupBlock scope(*this); - const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD); // In some cases, the type of the function argument will be different from @@ -556,20 +634,40 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // // To fix this we insert a bitcast here. QualType ArgTy = Info.arg_begin()->type; - DeclPtr = Builder.CreateBitCast(DeclPtr, ConvertType(ArgTy)); - - CallArgList Args; - Args.push_back(std::make_pair(RValue::get(DeclPtr), - getContext().getPointerType(D.getType()))); - - EmitCall(Info, F, Args); + { + DelayedCleanupBlock scope(*this); + + CallArgList Args; + Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr, + ConvertType(ArgTy))), + getContext().getPointerType(D.getType()))); + EmitCall(Info, F, Args); + } + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + + CallArgList Args; + Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr, + ConvertType(ArgTy))), + getContext().getPointerType(D.getType()))); + EmitCall(Info, F, Args); + } } if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) { - DelayedCleanupBlock scope(*this); - llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); - V = Builder.CreateLoad(V); - BuildBlockRelease(V); + { + DelayedCleanupBlock scope(*this); + llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); + V = Builder.CreateLoad(V); + BuildBlockRelease(V); + } + // FIXME: Turn this on and audit the codegen + if (0 && Exceptions) { + EHCleanupBlock Cleanup(*this); + llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); + V = Builder.CreateLoad(V); + BuildBlockRelease(V); + } } } @@ -591,10 +689,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { const llvm::Type *LTy = ConvertTypeForMem(Ty); if (LTy->isSingleValueType()) { // TODO: Alignment - std::string Name = D.getNameAsString(); - Name += ".addr"; DeclPtr = CreateTempAlloca(LTy); - DeclPtr->setName(Name.c_str()); + DeclPtr->setName(D.getNameAsString() + llvm::StringRef(".addr")); // Store the initial value into the alloca. EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty); diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp new file mode 100644 index 0000000..0b6ea5a --- /dev/null +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -0,0 +1,211 @@ +//===--- CGDeclCXX.cpp - Emit LLVM Code for C++ declarations --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with code generation of C++ declarations +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +using namespace clang; +using namespace CodeGen; + +static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, + llvm::Constant *DeclPtr) { + assert(D.hasGlobalStorage() && "VarDecl must have global storage!"); + assert(!D.getType()->isReferenceType() && + "Should not call EmitDeclInit on a reference!"); + + CodeGenModule &CGM = CGF.CGM; + ASTContext &Context = CGF.getContext(); + + const Expr *Init = D.getInit(); + QualType T = D.getType(); + bool isVolatile = Context.getCanonicalType(T).isVolatileQualified(); + + if (!CGF.hasAggregateLLVMType(T)) { + llvm::Value *V = CGF.EmitScalarExpr(Init); + CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, T); + } else if (T->isAnyComplexType()) { + CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); + } else { + CGF.EmitAggExpr(Init, DeclPtr, isVolatile); + + // Avoid generating destructor(s) for initialized objects. + if (!isa<CXXConstructExpr>(Init)) + return; + + const ConstantArrayType *Array = Context.getAsConstantArrayType(T); + if (Array) + T = Context.getBaseElementType(Array); + + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return; + + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialDestructor()) + return; + + CXXDestructorDecl *Dtor = RD->getDestructor(Context); + + llvm::Constant *DtorFn; + if (Array) { + DtorFn = + CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor, + Array, + DeclPtr); + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + DeclPtr = llvm::Constant::getNullValue(Int8PtrTy); + } else + DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); + + CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr); + } +} + +void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, + llvm::Constant *DeclPtr) { + + const Expr *Init = D.getInit(); + QualType T = D.getType(); + + if (!T->isReferenceType()) { + EmitDeclInit(*this, D, DeclPtr); + return; + } + + ErrorUnsupported(Init, "global variable that binds to a reference"); +} + +void +CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, + 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::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 +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 && + "thread safe statics are currently not supported!"); + + llvm::SmallString<256> GuardVName; + CGM.getMangleContext().mangleGuardVariable(&D, GuardVName); + + // Create the guard variable. + llvm::GlobalValue *GuardV = + new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), + false, GV->getLinkage(), + 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::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::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); + + if (D.getType()->isReferenceType()) { + QualType T = D.getType(); + // We don't want to pass true for IsInitializer here, because a static + // reference to a temporary does not extend its lifetime. + RValue RV = EmitReferenceBindingToExpr(D.getInit(), T, + /*IsInitializer=*/false); + EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T); + + } else + EmitDeclInit(*this, D, GV); + + Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), + 1), + Builder.CreateBitCast(GuardV, PtrTy)); + + EmitBlock(EndBlock); +} diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 420e275..b15b2e9 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -23,58 +23,83 @@ static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { // void *__cxa_allocate_exception(size_t thrown_size); const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); std::vector<const llvm::Type*> Args(1, SizeTy); - - const llvm::FunctionType *FTy = + + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()), Args, false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception"); } +static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) { + // void __cxa_free_exception(void *thrown_exception); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector<const llvm::Type*> Args(1, Int8PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception"); +} + static llvm::Constant *getThrowFn(CodeGenFunction &CGF) { - // void __cxa_throw (void *thrown_exception, std::type_info *tinfo, - // void (*dest) (void *) ); + // void __cxa_throw(void *thrown_exception, std::type_info *tinfo, + // void (*dest) (void *)); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); std::vector<const llvm::Type*> Args(3, Int8PtrTy); - - const llvm::FunctionType *FTy = + + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); } static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) { - // void __cxa_rethrow (); + // void __cxa_rethrow(); - const llvm::FunctionType *FTy = + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); } static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) { - // void* __cxa_begin_catch (); + // void* __cxa_begin_catch(); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); std::vector<const llvm::Type*> Args(1, Int8PtrTy); - - const llvm::FunctionType *FTy = + + const llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch"); } static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { - // void __cxa_end_catch (); + // void __cxa_end_catch(); - const llvm::FunctionType *FTy = + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch"); } +static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) { + // void __cxa_call_unexepcted(void *thrown_exception); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector<const llvm::Type*> Args(1, Int8PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); +} + // FIXME: Eventually this will all go into the backend. Set from the target for // now. static int using_sjlj_exceptions = 0; @@ -82,38 +107,64 @@ static int using_sjlj_exceptions = 0; static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); std::vector<const llvm::Type*> Args(1, Int8PtrTy); - - const llvm::FunctionType *FTy = + + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, false); - + if (using_sjlj_exceptions) return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow"); } +static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { + // void __terminate(); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev"); +} + // CopyObject - Utility to copy an object. Calls copy constructor as necessary. -// N is casted to the right type. -static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) { +// DestPtr is casted to the right type. +static void CopyObject(CodeGenFunction &CGF, const Expr *E, + llvm::Value *DestPtr, llvm::Value *ExceptionPtrPtr) { QualType ObjectType = E->getType(); // Store the throw exception in the exception object. if (!CGF.hasAggregateLLVMType(ObjectType)) { llvm::Value *Value = CGF.EmitScalarExpr(E); - const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); - - CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); + const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(); + + CGF.Builder.CreateStore(Value, + CGF.Builder.CreateBitCast(DestPtr, ValuePtrTy)); } else { - const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); - const CXXRecordDecl *RD; - RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); - llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); + const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(); + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); + + llvm::Value *This = CGF.Builder.CreateBitCast(DestPtr, Ty); if (RD->hasTrivialCopyConstructor()) { CGF.EmitAggExpr(E, This, false); } else if (CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(CGF.getContext(), 0)) { - // FIXME: region management + llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest(); + if (CGF.Exceptions) { + CodeGenFunction::EHCleanupBlock Cleanup(CGF); + llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF); + + // Load the exception pointer. + llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr); + CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr); + } + llvm::Value *Src = CGF.EmitLValue(E).getAddress(); + CGF.setInvokeDest(PrevLandingPad); + + llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); + PrevLandingPad = CGF.getInvokeDest(); + CGF.setInvokeDest(TerminateHandler); // Stolen from EmitClassAggrMemberwiseCopy llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, @@ -129,21 +180,22 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) { CopyCtor->getType()->getAs<FunctionType>()->getResultType(); CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), Callee, CallArgs, CopyCtor); - // FIXME: region management + CGF.setInvokeDest(PrevLandingPad); } else - CGF.ErrorUnsupported(E, "uncopyable object"); + llvm_unreachable("uncopyable object"); } } // CopyObject - Utility to copy an object. Calls copy constructor as necessary. // N is casted to the right type. static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, - llvm::Value *E, llvm::Value *N) { + bool WasPointer, llvm::Value *E, llvm::Value *N) { // Store the throw exception in the exception object. - if (!CGF.hasAggregateLLVMType(ObjectType)) { + if (WasPointer || !CGF.hasAggregateLLVMType(ObjectType)) { llvm::Value *Value = E; + if (!WasPointer) + Value = CGF.Builder.CreateLoad(Value); const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); - CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); } else { const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); @@ -154,7 +206,6 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, CGF.EmitAggregateCopy(This, E, ObjectType); } else if (CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(CGF.getContext(), 0)) { - // FIXME: region management llvm::Value *Src = E; // Stolen from EmitClassAggrMemberwiseCopy @@ -171,66 +222,181 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, CopyCtor->getType()->getAs<FunctionType>()->getResultType(); CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), Callee, CallArgs, CopyCtor); - // FIXME: region management } else - llvm::llvm_unreachable("uncopyable object"); + llvm_unreachable("uncopyable object"); } } void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { if (!E->getSubExpr()) { - Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); + if (getInvokeDest()) { + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); + Builder.CreateInvoke(getReThrowFn(*this), Cont, getInvokeDest()) + ->setDoesNotReturn(); + EmitBlock(Cont); + } else + Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); Builder.CreateUnreachable(); // Clear the insertion point to indicate we are in unreachable code. Builder.ClearInsertionPoint(); return; } - + QualType ThrowType = E->getSubExpr()->getType(); - // FIXME: Handle cleanup. - if (!CleanupEntries.empty()){ - ErrorUnsupported(E, "throw expression with cleanup entries"); - return; - } - + // Now allocate the exception object. const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; - + llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); - llvm::Value *ExceptionPtr = - Builder.CreateCall(AllocExceptionFn, + llvm::Value *ExceptionPtr = + Builder.CreateCall(AllocExceptionFn, llvm::ConstantInt::get(SizeTy, TypeSize), "exception"); - - CopyObject(*this, E->getSubExpr(), ExceptionPtr); + llvm::Value *ExceptionPtrPtr = + CreateTempAlloca(ExceptionPtr->getType(), "exception.ptr"); + Builder.CreateStore(ExceptionPtr, ExceptionPtrPtr); + + + CopyObject(*this, E->getSubExpr(), ExceptionPtr, ExceptionPtrPtr); + // Now throw the exception. const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - llvm::Constant *TypeInfo = CGM.GenerateRtti(ThrowType); + llvm::Constant *TypeInfo = CGM.GenerateRTTI(ThrowType); llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); - - llvm::CallInst *ThrowCall = - Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); - ThrowCall->setDoesNotReturn(); + + if (getInvokeDest()) { + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); + llvm::InvokeInst *ThrowCall = + Builder.CreateInvoke3(getThrowFn(*this), Cont, getInvokeDest(), + ExceptionPtr, TypeInfo, Dtor); + ThrowCall->setDoesNotReturn(); + EmitBlock(Cont); + } else { + llvm::CallInst *ThrowCall = + Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); + ThrowCall->setDoesNotReturn(); + } Builder.CreateUnreachable(); - + // Clear the insertion point to indicate we are in unreachable code. Builder.ClearInsertionPoint(); + + // FIXME: For now, emit a dummy basic block because expr emitters in generally + // are not ready to handle emitting expressions at unreachable points. + EnsureInsertPoint(); } -void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { -#if 1 - EmitStmt(S.getTryBlock()); - if (0) { - getBeginCatchFn(*this); - getEndCatchFn(*this); - getUnwindResumeOrRethrowFn(*this); - CopyObject(*this, QualType(), 0, 0); +void CodeGenFunction::EmitStartEHSpec(const Decl *D) { + const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); + if (FD == 0) + return; + const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>(); + if (Proto == 0) + return; + + assert(!Proto->hasAnyExceptionSpec() && "function with parameter pack"); + + if (!Proto->hasExceptionSpec()) + return; + + llvm::Constant *Personality = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty + (VMContext), + true), + "__gxx_personality_v0"); + Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + llvm::Value *llvm_eh_exception = + CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + const llvm::IntegerType *Int8Ty; + const llvm::PointerType *PtrToInt8Ty; + Int8Ty = llvm::Type::getInt8Ty(VMContext); + // C string type. Used in lots of places. + PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); + llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); + llvm::SmallVector<llvm::Value*, 8> SelectorArgs; + + llvm::BasicBlock *PrevLandingPad = getInvokeDest(); + llvm::BasicBlock *EHSpecHandler = createBasicBlock("ehspec.handler"); + llvm::BasicBlock *Match = createBasicBlock("match"); + llvm::BasicBlock *Unwind = 0; + + assert(PrevLandingPad == 0 && "EHSpec has invoke context"); + (void)PrevLandingPad; + + llvm::BasicBlock *Cont = createBasicBlock("cont"); + + EmitBranchThroughCleanup(Cont); + + // Emit the statements in the try {} block + setInvokeDest(EHSpecHandler); + + EmitBlock(EHSpecHandler); + // Exception object + llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); + + SelectorArgs.push_back(Exc); + SelectorArgs.push_back(Personality); + SelectorArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + Proto->getNumExceptions()+1)); + + for (unsigned i = 0; i < Proto->getNumExceptions(); ++i) { + QualType Ty = Proto->getExceptionType(i); + llvm::Value *EHType + = CGM.GenerateRTTI(Ty.getNonReferenceType()); + SelectorArgs.push_back(EHType); } -#else - // FIXME: The below is still just a sketch of the code we need. + if (Proto->getNumExceptions()) + SelectorArgs.push_back(Null); + + // Find which handler was matched. + llvm::Value *Selector + = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), + SelectorArgs.end(), "selector"); + if (Proto->getNumExceptions()) { + Unwind = createBasicBlock("Unwind"); + + Builder.CreateStore(Exc, RethrowPtr); + Builder.CreateCondBr(Builder.CreateICmpSLT(Selector, + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + 0)), + Match, Unwind); + + EmitBlock(Match); + } + Builder.CreateCall(getUnexpectedFn(*this), Exc)->setDoesNotReturn(); + Builder.CreateUnreachable(); + + if (Proto->getNumExceptions()) { + EmitBlock(Unwind); + Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), + Builder.CreateLoad(RethrowPtr)); + Builder.CreateUnreachable(); + } + + EmitBlock(Cont); +} + +void CodeGenFunction::EmitEndEHSpec(const Decl *D) { + const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); + if (FD == 0) + return; + const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>(); + if (Proto == 0) + return; + + if (!Proto->hasExceptionSpec()) + return; + + setInvokeDest(0); +} + +void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { // Pointer to the personality function llvm::Constant *Personality = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty @@ -238,31 +404,66 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { true), "__gxx_personality_v0"); Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + llvm::Value *llvm_eh_exception = + CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGM.getIntrinsic(llvm::Intrinsic::eh_selector); llvm::BasicBlock *PrevLandingPad = getInvokeDest(); llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); -#if 0 llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); -#endif llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); -#if 0 // Push an EH context entry, used for handling rethrows. PushCleanupBlock(FinallyBlock); -#endif // Emit the statements in the try {} block setInvokeDest(TryHandler); - EmitStmt(S.getTryBlock()); + // 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); + + 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); + llvm::BasicBlock *TerminateHandler = getTerminateHandler(); + // Emit the handlers EmitBlock(TryHandler); - + const llvm::IntegerType *Int8Ty; const llvm::PointerType *PtrToInt8Ty; Int8Ty = llvm::Type::getInt8Ty(VMContext); @@ -270,16 +471,14 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); llvm::SmallVector<llvm::Value*, 8> SelectorArgs; - llvm::Value *llvm_eh_exception = - CGM.getIntrinsic(llvm::Intrinsic::eh_exception); - llvm::Value *llvm_eh_selector = - CGM.getIntrinsic(llvm::Intrinsic::eh_selector); llvm::Value *llvm_eh_typeid_for = CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); // Exception object llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); + llvm::SmallVector<llvm::Value*, 8> Args; + Args.clear(); SelectorArgs.push_back(Exc); SelectorArgs.push_back(Personality); @@ -288,7 +487,8 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { const CXXCatchStmt *C = S.getHandler(i); VarDecl *CatchParam = C->getExceptionDecl(); if (CatchParam) { - llvm::Value *EHType = CGM.GenerateRtti(C->getCaughtType().getNonReferenceType()); + llvm::Value *EHType + = CGM.GenerateRTTI(C->getCaughtType().getNonReferenceType()); SelectorArgs.push_back(EHType); } else { // null indicates catch all @@ -334,27 +534,31 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc); - // Bind the catch parameter if it exists. - if (CatchParam) { - QualType CatchType = CatchParam->getType().getNonReferenceType(); - if (!CatchType.getTypePtr()->isPointerType()) - CatchType = getContext().getPointerType(CatchType); - ExcObject = - Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); - // CatchParam is a ParmVarDecl because of the grammar - // construction used to handle this, but for codegen purposes - // we treat this as a local decl. - EmitLocalBlockVarDecl(*CatchParam); -#if 0 - // FIXME: objects with ctors, references - Builder.CreateStore(ExcObject, GetAddrOfLocalVar(CatchParam)); -#else - CopyObject(*this, CatchParam->getType().getNonReferenceType(), - ExcObject, GetAddrOfLocalVar(CatchParam)); -#endif + { + CleanupScope CatchScope(*this); + // Bind the catch parameter if it exists. + if (CatchParam) { + QualType CatchType = CatchParam->getType().getNonReferenceType(); + setInvokeDest(TerminateHandler); + bool WasPointer = true; + if (!CatchType.getTypePtr()->isPointerType()) { + if (!isa<ReferenceType>(CatchParam->getType())) + WasPointer = false; + CatchType = getContext().getPointerType(CatchType); + } + ExcObject = Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); + EmitLocalBlockVarDecl(*CatchParam); + // FIXME: we need to do this sooner so that the EH region for the + // cleanup doesn't start until after the ctor completes, use a decl + // init? + CopyObject(*this, CatchParam->getType().getNonReferenceType(), + WasPointer, ExcObject, GetAddrOfLocalVar(CatchParam)); + setInvokeDest(MatchHandler); + } + + EmitStmt(CatchBody); } - EmitStmt(CatchBody); EmitBranchThroughCleanup(FinallyEnd); EmitBlock(MatchHandler); @@ -362,7 +566,7 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); // We are required to emit this call to satisfy LLVM, even // though we don't use the result. - llvm::SmallVector<llvm::Value*, 8> Args; + Args.clear(); Args.push_back(Exc); Args.push_back(Personality); Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), @@ -375,45 +579,32 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { EmitBlock(MatchEnd); - // Unfortunately, we also have to generate another EH frame here - // in case this throws. - llvm::BasicBlock *MatchEndHandler = - createBasicBlock("match.end.handler"); - llvm::BasicBlock *Cont = createBasicBlock("myinvoke.cont"); + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); Builder.CreateInvoke(getEndCatchFn(*this), - Cont, MatchEndHandler, + Cont, TerminateHandler, Args.begin(), Args.begin()); - EmitBlock(Cont); if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); if (Info.EndBlock) EmitBlock(Info.EndBlock); - EmitBlock(MatchEndHandler); Exc = Builder.CreateCall(llvm_eh_exception, "exc"); - // We are required to emit this call to satisfy LLVM, even - // though we don't use the result. - Args.clear(); - Args.push_back(Exc); - Args.push_back(Personality); - Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - 0)); - Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); if (Next) EmitBlock(Next); } - if (!HasCatchAll) + if (!HasCatchAll) { + Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); + } CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); setInvokeDest(PrevLandingPad); -#if 0 EmitBlock(FinallyBlock); if (Info.SwitchBlock) @@ -423,13 +614,122 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { // Branch around the rethrow code. EmitBranch(FinallyEnd); -#endif EmitBlock(FinallyRethrow); - Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), - Builder.CreateLoad(RethrowPtr)); + // FIXME: Eventually we can chain the handlers together and just do a call + // here. + if (getInvokeDest()) { + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); + Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont, + getInvokeDest(), + Builder.CreateLoad(RethrowPtr)); + EmitBlock(Cont); + } else + Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), + Builder.CreateLoad(RethrowPtr)); + Builder.CreateUnreachable(); EmitBlock(FinallyEnd); -#endif +} + +CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() { + llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont"); + CGF.EmitBranch(Cont1); + CGF.setInvokeDest(PreviousInvokeDest); + + + CGF.EmitBlock(CleanupHandler); + + llvm::Constant *Personality = + CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty + (CGF.VMContext), + true), + "__gxx_personality_v0"); + Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty); + llvm::Value *llvm_eh_exception = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + + llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); + const llvm::IntegerType *Int8Ty; + const llvm::PointerType *PtrToInt8Ty; + Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext); + // C string type. Used in lots of places. + PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); + llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); + llvm::SmallVector<llvm::Value*, 8> Args; + Args.clear(); + Args.push_back(Exc); + Args.push_back(Personality); + Args.push_back(Null); + CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + + CGF.EmitBlock(CleanupEntryBB); + + CGF.EmitBlock(Cont1); + + if (CGF.getInvokeDest()) { + llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); + CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont, + CGF.getInvokeDest(), Exc); + CGF.EmitBlock(Cont); + } else + CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc); + + CGF.Builder.CreateUnreachable(); + + CGF.EmitBlock(Cont); + if (CGF.Exceptions) + CGF.setInvokeDest(CleanupHandler); +} + +llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { + if (TerminateHandler) + return TerminateHandler; + + llvm::BasicBlock *Cont = 0; + + if (HaveInsertPoint()) { + Cont = createBasicBlock("cont"); + EmitBranch(Cont); + } + + llvm::Constant *Personality = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty + (VMContext), + true), + "__gxx_personality_v0"); + Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + llvm::Value *llvm_eh_exception = + CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + + // Set up terminate handler + TerminateHandler = createBasicBlock("terminate.handler"); + EmitBlock(TerminateHandler); + llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + // We are required to emit this call to satisfy LLVM, even + // though we don't use the result. + llvm::SmallVector<llvm::Value*, 8> Args; + Args.push_back(Exc); + Args.push_back(Personality); + Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + 1)); + Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + llvm::CallInst *TerminateCall = + Builder.CreateCall(getTerminateFn(*this)); + TerminateCall->setDoesNotReturn(); + TerminateCall->setDoesNotThrow(); + Builder.CreateUnreachable(); + + // Clear the insertion point to indicate we are in unreachable code. + Builder.ClearInsertionPoint(); + + if (Cont) + EmitBlock(Cont); + + return TerminateHandler; } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 63fca2d..e6bbfa8 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -17,6 +17,8 @@ #include "CGObjCRuntime.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "llvm/Intrinsics.h" +#include "clang/CodeGen/CodeGenOptions.h" #include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; @@ -38,6 +40,21 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty, /// expression and compare the result against zero, returning an Int1Ty value. llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) { QualType BoolTy = getContext().BoolTy; + if (E->getType()->isMemberFunctionPointerType()) { + llvm::Value *Ptr = CreateTempAlloca(ConvertType(E->getType())); + EmitAggExpr(E, Ptr, /*VolatileDest=*/false); + + // Get the pointer. + llvm::Value *FuncPtr = Builder.CreateStructGEP(Ptr, 0, "src.ptr"); + FuncPtr = Builder.CreateLoad(FuncPtr); + + llvm::Value *IsNotNull = + Builder.CreateICmpNE(FuncPtr, + llvm::Constant::getNullValue(FuncPtr->getType()), + "tobool"); + + return IsNotNull; + } if (!E->getType()->isAnyComplexType()) return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy); @@ -137,8 +154,19 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, const CXXDestructorDecl *Dtor = ClassDecl->getDestructor(getContext()); - DelayedCleanupBlock scope(*this); - EmitCXXDestructorCall(Dtor, Dtor_Complete, Val.getAggregateAddr()); + { + DelayedCleanupBlock Scope(*this); + EmitCXXDestructorCall(Dtor, Dtor_Complete, + Val.getAggregateAddr()); + + // Make sure to jump to the exit block. + EmitBranch(Scope.getCleanupExitBlock()); + } + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + EmitCXXDestructorCall(Dtor, Dtor_Complete, + Val.getAggregateAddr()); + } } } } @@ -237,6 +265,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { switch (E->getStmtClass()) { default: return EmitUnsupportedLValue(E, "l-value expression"); + case Expr::ObjCIsaExprClass: + return EmitObjCIsaExpr(cast<ObjCIsaExpr>(E)); case Expr::BinaryOperatorClass: return EmitBinaryOperatorLValue(cast<BinaryOperator>(E)); case Expr::CallExprClass: @@ -330,13 +360,8 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr, if (Ty->isBooleanType()) { // Bool can have different representation in memory than in registers. - const llvm::Type *SrcTy = Value->getType(); const llvm::PointerType *DstPtr = cast<llvm::PointerType>(Addr->getType()); - if (DstPtr->getElementType() != SrcTy) { - const llvm::Type *MemTy = - llvm::PointerType::get(SrcTy, DstPtr->getAddressSpace()); - Addr = Builder.CreateBitCast(Addr, MemTy, "storetmp"); - } + Value = Builder.CreateIntCast(Value, DstPtr->getElementType(), false); } Builder.CreateStore(Value, Addr, Volatile); } @@ -408,8 +433,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, // Shift to proper location. if (StartBit) - Val = Builder.CreateLShr(Val, llvm::ConstantInt::get(EltTy, StartBit), - "bf.lo"); + Val = Builder.CreateLShr(Val, StartBit, "bf.lo"); // Mask off unused bits. llvm::Constant *LowMask = llvm::ConstantInt::get(VMContext, @@ -431,8 +455,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, HighVal = Builder.CreateAnd(HighVal, HighMask, "bf.lo.cleared"); // Shift to proper location and or in to bitfield value. - HighVal = Builder.CreateShl(HighVal, - llvm::ConstantInt::get(EltTy, LowBits)); + HighVal = Builder.CreateShl(HighVal, LowBits); Val = Builder.CreateOr(Val, HighVal, "bf.val"); } @@ -618,8 +641,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // LowVal = (LowVal & InvMask) | (NewVal << StartBit), // with the shift of NewVal implicitly stripping the high bits. llvm::Value *NewLowVal = - Builder.CreateShl(NewVal, llvm::ConstantInt::get(EltTy, StartBit), - "bf.value.lo"); + Builder.CreateShl(NewVal, StartBit, "bf.value.lo"); LowVal = Builder.CreateAnd(LowVal, InvMask, "bf.prev.lo.cleared"); LowVal = Builder.CreateOr(LowVal, NewLowVal, "bf.new.lo"); @@ -645,8 +667,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // where the high bits of NewVal have already been cleared and the // shift stripping the low bits. llvm::Value *NewHighVal = - Builder.CreateLShr(NewVal, llvm::ConstantInt::get(EltTy, LowBits), - "bf.value.high"); + Builder.CreateLShr(NewVal, LowBits, "bf.value.high"); HighVal = Builder.CreateAnd(HighVal, InvMask, "bf.prev.hi.cleared"); HighVal = Builder.CreateOr(HighVal, NewHighVal, "bf.new.hi"); @@ -993,6 +1014,36 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { } } +llvm::BasicBlock *CodeGenFunction::getTrapBB() { + const CodeGenOptions &GCO = CGM.getCodeGenOpts(); + + // If we are not optimzing, don't collapse all calls to trap in the function + // to the same call, that way, in the debugger they can see which operation + // did in fact fail. If we are optimizing, we collpase all call to trap down + // to just one per function to save on codesize. + if (GCO.OptimizationLevel + && TrapBB) + return TrapBB; + + llvm::BasicBlock *Cont = 0; + if (HaveInsertPoint()) { + Cont = createBasicBlock("cont"); + EmitBranch(Cont); + } + TrapBB = createBasicBlock("trap"); + EmitBlock(TrapBB); + + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap, 0, 0); + llvm::CallInst *TrapCall = Builder.CreateCall(F); + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + Builder.CreateUnreachable(); + + if (Cont) + EmitBlock(Cont); + return TrapBB; +} + LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { // The index must always be an integer, which is not an aggregate. Emit it. llvm::Value *Idx = EmitScalarExpr(E->getIdx()); @@ -1021,6 +1072,24 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { llvm::IntegerType::get(VMContext, LLVMPointerWidth), IdxSigned, "idxprom"); + if (CatchUndefined) { + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E->getBase())) { + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr())) { + if (ICE->getCastKind() == CastExpr::CK_ArrayToPointerDecay) { + if (const ConstantArrayType *CAT + = getContext().getAsConstantArrayType(DRE->getType())) { + llvm::APInt Size = CAT->getSize(); + llvm::BasicBlock *Cont = createBasicBlock("cont"); + Builder.CreateCondBr(Builder.CreateICmpULE(Idx, + llvm::ConstantInt::get(Idx->getType(), Size)), + Cont, getTrapBB()); + EmitBlock(Cont); + } + } + } + } + } + // We know that the pointer points to a type of the correct size, unless the // size is a VLA or Objective-C interface. llvm::Value *Address = 0; @@ -1417,7 +1486,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl)) return EmitCXXOperatorMemberCallExpr(CE, MD); - if (isa<CXXPseudoDestructorExpr>(E->getCallee())) { + if (isa<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) { // C++ [expr.pseudo]p1: // The result shall only be used as the operand for the function call // operator (), and the result of such a call has type void. The only @@ -1436,6 +1505,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { // Comma expressions just emit their LHS then their RHS as an l-value. if (E->getOpcode() == BinaryOperator::Comma) { EmitAnyExpr(E->getLHS()); + EnsureInsertPoint(); return EmitLValue(E->getRHS()); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index d225d90..2c122eb 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -120,7 +120,7 @@ public: void EmitInitializationToLValue(Expr *E, LValue Address); void EmitNullInitializationToLValue(LValue Address, QualType T); // case Expr::ChooseExprClass: - + void VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); } }; } // end anonymous namespace. @@ -502,21 +502,16 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) { void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { #if 0 - // FIXME: Disabled while we figure out what to do about - // test/CodeGen/bitfield.c + // FIXME: Assess perf here? Figure out what cases are worth optimizing here + // (Length of globals? Chunks of zeroed-out space?). // // If we can, prefer a copy from a global; this is a lot less code for long // globals, and it's easier for the current optimizers to analyze. - // FIXME: Should we really be doing this? Should we try to avoid cases where - // we emit a global with a lot of zeros? Should we try to avoid short - // globals? - if (E->isConstantInitializer(CGF.getContext(), 0)) { - llvm::Constant* C = CGF.CGM.EmitConstantExpr(E, &CGF); + if (llvm::Constant* C = CGF.CGM.EmitConstantExpr(E, E->getType(), &CGF)) { llvm::GlobalVariable* GV = - new llvm::GlobalVariable(C->getType(), true, - llvm::GlobalValue::InternalLinkage, - C, "", &CGF.CGM.getModule(), 0); - EmitFinalDestCopy(E, LValue::MakeAddr(GV, 0)); + new llvm::GlobalVariable(CGF.CGM.getModule(), C->getType(), true, + llvm::GlobalValue::InternalLinkage, C, ""); + EmitFinalDestCopy(E, LValue::MakeAddr(GV, Qualifiers())); return; } #endif diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index b982c15..150f11e 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -15,13 +15,8 @@ using namespace clang; using namespace CodeGen; -static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { - if (!E->isArray()) - return 0; - - QualType T = E->getAllocatedType(); - - const RecordType *RT = T->getAs<RecordType>(); +static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) { + const RecordType *RT = ElementType->getAs<RecordType>(); if (!RT) return 0; @@ -31,13 +26,59 @@ static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { // Check if the class has a trivial destructor. if (RD->hasTrivialDestructor()) { - // FIXME: Check for a two-argument delete. - return 0; - } + // Check if the usual deallocation function takes two arguments. + const CXXMethodDecl *UsualDeallocationFunction = 0; + + DeclarationName OpName = + Ctx.DeclarationNames.getCXXOperatorName(OO_Array_Delete); + DeclContext::lookup_const_iterator Op, OpEnd; + for (llvm::tie(Op, OpEnd) = RD->lookup(OpName); + Op != OpEnd; ++Op) { + const CXXMethodDecl *Delete = cast<CXXMethodDecl>(*Op); + + if (Delete->isUsualDeallocationFunction()) { + UsualDeallocationFunction = Delete; + break; + } + } + + // No usual deallocation function, we don't need a cookie. + if (!UsualDeallocationFunction) + return 0; + + // The usual deallocation function doesn't take a size_t argument, so we + // don't need a cookie. + if (UsualDeallocationFunction->getNumParams() == 1) + return 0; + + assert(UsualDeallocationFunction->getNumParams() == 2 && + "Unexpected deallocation function type!"); + } - // Padding is the maximum of sizeof(size_t) and alignof(T) + // Padding is the maximum of sizeof(size_t) and alignof(ElementType) return std::max(Ctx.getTypeSize(Ctx.getSizeType()), - static_cast<uint64_t>(Ctx.getTypeAlign(T))) / 8; + static_cast<uint64_t>(Ctx.getTypeAlign(ElementType))) / 8; +} + +static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { + if (!E->isArray()) + return 0; + + // No cookie is required if the new operator being used is + // ::operator new[](size_t, void*). + const FunctionDecl *OperatorNew = E->getOperatorNew(); + if (OperatorNew->getDeclContext()->getLookupContext()->isFileContext()) { + if (OperatorNew->getNumParams() == 2) { + CanQualType ParamType = + Ctx.getCanonicalType(OperatorNew->getParamDecl(1)->getType()); + + if (ParamType == Ctx.VoidPtrTy) + return 0; + } + } + + return CalculateCookiePadding(Ctx, E->getAllocatedType()); + QualType T = E->getAllocatedType(); } static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, @@ -237,6 +278,39 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { return NewPtr; } +static std::pair<llvm::Value *, llvm::Value *> +GetAllocatedObjectPtrAndNumElements(CodeGenFunction &CGF, + llvm::Value *Ptr, QualType DeleteTy) { + QualType SizeTy = CGF.getContext().getSizeType(); + const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy); + + uint64_t DeleteTypeAlign = CGF.getContext().getTypeAlign(DeleteTy); + uint64_t CookiePadding = std::max(CGF.getContext().getTypeSize(SizeTy), + DeleteTypeAlign) / 8; + assert(CookiePadding && "CookiePadding should not be 0."); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + uint64_t CookieOffset = + CookiePadding - CGF.getContext().getTypeSize(SizeTy) / 8; + + llvm::Value *AllocatedObjectPtr = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy); + AllocatedObjectPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, + -CookiePadding); + + llvm::Value *NumElementsPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, + CookieOffset); + NumElementsPtr = + CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo()); + + llvm::Value *NumElements = CGF.Builder.CreateLoad(NumElementsPtr); + NumElements = + CGF.Builder.CreateIntCast(NumElements, SizeLTy, /*isSigned=*/false); + + return std::make_pair(AllocatedObjectPtr, NumElements); +} + void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, llvm::Value *Ptr, QualType DeleteTy) { @@ -245,17 +319,37 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, CallArgList DeleteArgs; + // Check if we need to pass the size to the delete operator. + llvm::Value *Size = 0; + QualType SizeTy; + if (DeleteFTy->getNumArgs() == 2) { + SizeTy = DeleteFTy->getArgType(1); + uint64_t DeleteTypeSize = getContext().getTypeSize(DeleteTy) / 8; + Size = llvm::ConstantInt::get(ConvertType(SizeTy), DeleteTypeSize); + } + + if (DeleteFD->getOverloadedOperator() == OO_Array_Delete && + + CalculateCookiePadding(getContext(), DeleteTy)) { + // We need to get the number of elements in the array from the cookie. + llvm::Value *AllocatedObjectPtr; + llvm::Value *NumElements; + llvm::tie(AllocatedObjectPtr, NumElements) = + GetAllocatedObjectPtrAndNumElements(*this, Ptr, DeleteTy); + + // Multiply the size with the number of elements. + if (Size) + Size = Builder.CreateMul(NumElements, Size); + + Ptr = AllocatedObjectPtr; + } + QualType ArgTy = DeleteFTy->getArgType(0); llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy)); DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy)); - if (DeleteFTy->getNumArgs() == 2) { - QualType SizeTy = DeleteFTy->getArgType(1); - uint64_t SizeVal = getContext().getTypeSize(DeleteTy) / 8; - llvm::Constant *Size = llvm::ConstantInt::get(ConvertType(SizeTy), - SizeVal); + if (Size) DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy)); - } // Emit the call to delete. EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(), @@ -300,34 +394,13 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { if (!RD->hasTrivialDestructor()) { const CXXDestructorDecl *Dtor = RD->getDestructor(getContext()); if (E->isArrayForm()) { - QualType SizeTy = getContext().getSizeType(); - uint64_t CookiePadding = std::max(getContext().getTypeSize(SizeTy), - static_cast<uint64_t>(getContext().getTypeAlign(DeleteTy))) / 8; - if (CookiePadding) { - llvm::Type *Ptr8Ty = - llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - uint64_t CookieOffset = - CookiePadding - getContext().getTypeSize(SizeTy) / 8; - llvm::Value *AllocatedObjectPtr = - Builder.CreateConstInBoundsGEP1_64( - Builder.CreateBitCast(Ptr, Ptr8Ty), -CookiePadding); - llvm::Value *NumElementsPtr = - Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, - CookieOffset); - NumElementsPtr = Builder.CreateBitCast(NumElementsPtr, - ConvertType(SizeTy)->getPointerTo()); - - llvm::Value *NumElements = - Builder.CreateLoad(NumElementsPtr); - NumElements = - Builder.CreateIntCast(NumElements, - llvm::Type::getInt64Ty(VMContext), false, - "count.tmp"); - EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr); - Ptr = AllocatedObjectPtr; - } - } - else if (Dtor->isVirtual()) { + llvm::Value *AllocatedObjectPtr; + llvm::Value *NumElements; + llvm::tie(AllocatedObjectPtr, NumElements) = + GetAllocatedObjectPtrAndNumElements(*this, Ptr, DeleteTy); + + EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr); + } else if (Dtor->isVirtual()) { const llvm::Type *Ty = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(Dtor), /*isVariadic=*/false); @@ -352,18 +425,10 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { QualType Ty = E->getType(); const llvm::Type *LTy = ConvertType(Ty)->getPointerTo(); - if (E->isTypeOperand()) { - Ty = E->getTypeOperand(); - CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); - Ty = CanTy.getUnqualifiedType().getNonReferenceType(); - if (const RecordType *RT = Ty->getAs<RecordType>()) { - const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->isPolymorphic()) - return Builder.CreateBitCast(CGM.GenerateRttiRef(RD), LTy); - return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy); - } - return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy); - } + + if (E->isTypeOperand()) + return Builder.CreateBitCast(CGM.GetAddrOfRTTI(E->getTypeOperand()), LTy); + Expr *subE = E->getExprOperand(); Ty = subE->getType(); CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); @@ -404,9 +469,9 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { V = Builder.CreateLoad(V); return V; } - return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy); + return Builder.CreateBitCast(CGM.GenerateRTTI(RD), LTy); } - return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy); + return Builder.CreateBitCast(CGM.GenerateRTTI(Ty), LTy); } llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, @@ -485,8 +550,8 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, // FIXME: Calculate better hint. llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL); - llvm::Value *SrcArg = CGM.GenerateRttiRef(SrcTy); - llvm::Value *DstArg = CGM.GenerateRttiRef(DstTy); + llvm::Value *SrcArg = CGM.GenerateRTTIRef(SrcTy); + llvm::Value *DstArg = CGM.GenerateRTTIRef(DstTy); V = Builder.CreateBitCast(V, PtrToInt8Ty); V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"), V, SrcArg, DstArg, hint); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 9289f78..d428983 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -167,7 +167,11 @@ class ConstStructBuilder { } // Or in the bits that go into the previous byte. - Tmp |= cast<llvm::ConstantInt>(Elements.back())->getValue(); + if (llvm::ConstantInt *Val = dyn_cast<llvm::ConstantInt>(Elements.back())) + Tmp |= Val->getValue(); + else + assert(isa<llvm::UndefValue>(Elements.back())); + Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp); if (FitsCompletelyInPreviousByte) diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index c1cbecc..2f31c05 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -167,6 +167,12 @@ public: return CGF.EmitObjCMessageExpr(E).getScalarVal(); } + Value *VisitObjCIsaExpr(ObjCIsaExpr *E) { + LValue LV = CGF.EmitObjCIsaExpr(E); + Value *V = CGF.EmitLoadOfLValue(LV, E->getType()).getScalarVal(); + return V; + } + Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E); Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E); Value *VisitMemberExpr(MemberExpr *E); @@ -257,6 +263,10 @@ public: CGF.EmitCXXDeleteExpr(E); return 0; } + Value *VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) { + return llvm::ConstantInt::get(Builder.getInt1Ty(), + E->EvaluateTrait(CGF.getContext())); + } Value *VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) { // C++ [expr.pseudo]p1: @@ -798,6 +808,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { //assert(0 && "Unknown cast kind!"); break; + case CastExpr::CK_AnyPointerToObjCPointerCast: + case CastExpr::CK_AnyPointerToBlockPointerCast: case CastExpr::CK_BitCast: { Value *Src = Visit(const_cast<Expr*>(E)); return Builder.CreateBitCast(Src, ConvertType(DestTy)); @@ -943,34 +955,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { case CastExpr::CK_FloatingCast: return EmitScalarConversion(Visit(E), E->getType(), DestTy); - case CastExpr::CK_MemberPointerToBoolean: { - const MemberPointerType* T = E->getType()->getAs<MemberPointerType>(); - - if (T->getPointeeType()->isFunctionType()) { - // We have a member function pointer. - llvm::Value *Ptr = CGF.CreateTempAlloca(ConvertType(E->getType())); - - CGF.EmitAggExpr(E, Ptr, /*VolatileDest=*/false); - - // Get the pointer. - llvm::Value *FuncPtr = Builder.CreateStructGEP(Ptr, 0, "src.ptr"); - FuncPtr = Builder.CreateLoad(FuncPtr); - - llvm::Value *IsNotNull = - Builder.CreateICmpNE(FuncPtr, - llvm::Constant::getNullValue(FuncPtr->getType()), - "tobool"); - - return IsNotNull; - } - - // We have a regular member pointer. - Value *Ptr = Visit(const_cast<Expr*>(E)); - llvm::Value *IsNotNull = - Builder.CreateICmpNE(Ptr, CGF.CGM.EmitNullConstant(E->getType()), - "tobool"); - return IsNotNull; - } + case CastExpr::CK_MemberPointerToBoolean: + return CGF.EvaluateExprAsBool(E); } // Handle cases where the source is an non-complex type. @@ -1540,6 +1526,16 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) { if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); + if (CGF.CatchUndefined + && isa<llvm::IntegerType>(Ops.LHS->getType())) { + unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth(); + llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); + CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS, + llvm::ConstantInt::get(RHS->getType(), Width)), + Cont, CGF.getTrapBB()); + CGF.EmitBlock(Cont); + } + return Builder.CreateShl(Ops.LHS, RHS, "shl"); } @@ -1550,6 +1546,16 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); + if (CGF.CatchUndefined + && isa<llvm::IntegerType>(Ops.LHS->getType())) { + unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth(); + llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); + CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS, + llvm::ConstantInt::get(RHS->getType(), Width)), + Cont, CGF.getTrapBB()); + CGF.EmitBlock(Cont); + } + if (Ops.Ty->isUnsignedIntegerType()) return Builder.CreateLShr(Ops.LHS, RHS, "shr"); return Builder.CreateAShr(Ops.LHS, RHS, "shr"); @@ -1560,7 +1566,34 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, TestAndClearIgnoreResultAssign(); Value *Result; QualType LHSTy = E->getLHS()->getType(); - if (!LHSTy->isAnyComplexType()) { + if (LHSTy->isMemberFunctionPointerType()) { + Value *LHSPtr = CGF.EmitAnyExprToTemp(E->getLHS()).getAggregateAddr(); + Value *RHSPtr = CGF.EmitAnyExprToTemp(E->getRHS()).getAggregateAddr(); + llvm::Value *LHSFunc = Builder.CreateStructGEP(LHSPtr, 0); + LHSFunc = Builder.CreateLoad(LHSFunc); + llvm::Value *RHSFunc = Builder.CreateStructGEP(RHSPtr, 0); + RHSFunc = Builder.CreateLoad(RHSFunc); + Value *ResultF = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, + LHSFunc, RHSFunc, "cmp.func"); + Value *NullPtr = llvm::Constant::getNullValue(LHSFunc->getType()); + Value *ResultNull = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, + LHSFunc, NullPtr, "cmp.null"); + llvm::Value *LHSAdj = Builder.CreateStructGEP(LHSPtr, 1); + LHSAdj = Builder.CreateLoad(LHSAdj); + llvm::Value *RHSAdj = Builder.CreateStructGEP(RHSPtr, 1); + RHSAdj = Builder.CreateLoad(RHSAdj); + Value *ResultA = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, + LHSAdj, RHSAdj, "cmp.adj"); + if (E->getOpcode() == BinaryOperator::EQ) { + Result = Builder.CreateOr(ResultNull, ResultA, "or.na"); + Result = Builder.CreateAnd(Result, ResultF, "and.f"); + } else { + assert(E->getOpcode() == BinaryOperator::NE && + "Member pointer comparison other than == or != ?"); + Result = Builder.CreateAnd(ResultNull, ResultA, "and.na"); + Result = Builder.CreateOr(Result, ResultF, "or.f"); + } + } else if (!LHSTy->isAnyComplexType()) { Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); @@ -1868,10 +1901,11 @@ VisitConditionalOperator(const ConditionalOperator *E) { CGF.EmitBlock(ContBlock); - if (!LHS || !RHS) { - assert(E->getType()->isVoidType() && "Non-void value should have a value"); - return 0; - } + // If the LHS or RHS is a throw expression, it will be legitimately null. + if (!LHS) + return RHS; + if (!RHS) + return LHS; // Create a PHI node for the real part. llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), "cond"); @@ -1976,3 +2010,22 @@ llvm::Value *CodeGenFunction::EmitVector(llvm::Value * const *Vals, return Vec; } + +LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) { + llvm::Value *V; + // object->isa or (*object).isa + // Generate code as for: *(Class*)object + Expr *BaseExpr = E->getBase(); + if (E->isArrow()) + V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr); + else + V = EmitLValue(BaseExpr).getAddress(); + + // build Class* type + const llvm::Type *ClassPtrTy = ConvertType(E->getType()); + ClassPtrTy = ClassPtrTy->getPointerTo(); + V = Builder.CreateBitCast(V, ClassPtrTy); + LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); + return LV; +} + diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 2e8ab29..fb920f0 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -28,6 +28,7 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetData.h" #include <cstdio> @@ -905,6 +906,13 @@ protected: const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes); + /// PushProtocolProperties - Push protocol's property on the input stack. + void PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet, + std::vector<llvm::Constant*> &Properties, + const Decl *Container, + const ObjCProtocolDecl *PROTO, + const ObjCCommonTypesHelper &ObjCTypes); + /// GetProtocolRef - Return a reference to the internal protocol /// description, creating an empty one if it has not been /// defined. The return value has type ProtocolPtrTy. @@ -1793,6 +1801,26 @@ CGObjCMac::EmitProtocolList(llvm::Twine Name, return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy); } +void CGObjCCommonMac::PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet, + std::vector<llvm::Constant*> &Properties, + const Decl *Container, + const ObjCProtocolDecl *PROTO, + const ObjCCommonTypesHelper &ObjCTypes) { + std::vector<llvm::Constant*> Prop(2); + for (ObjCProtocolDecl::protocol_iterator P = PROTO->protocol_begin(), + E = PROTO->protocol_end(); P != E; ++P) + PushProtocolProperties(PropertySet, Properties, Container, (*P), ObjCTypes); + for (ObjCContainerDecl::prop_iterator I = PROTO->prop_begin(), + E = PROTO->prop_end(); I != E; ++I) { + const ObjCPropertyDecl *PD = *I; + if (!PropertySet.insert(PD->getIdentifier())) + continue; + Prop[0] = GetPropertyName(PD->getIdentifier()); + Prop[1] = GetPropertyTypeString(PD, Container); + Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy, Prop)); + } +} + /* struct _objc_property { const char * const name; @@ -1810,14 +1838,20 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(llvm::Twine Name, const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes) { std::vector<llvm::Constant*> Properties, Prop(2); + llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet; for (ObjCContainerDecl::prop_iterator I = OCD->prop_begin(), E = OCD->prop_end(); I != E; ++I) { const ObjCPropertyDecl *PD = *I; + PropertySet.insert(PD->getIdentifier()); Prop[0] = GetPropertyName(PD->getIdentifier()); Prop[1] = GetPropertyTypeString(PD, Container); Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy, Prop)); } + if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) + for (ObjCInterfaceDecl::protocol_iterator P = OID->protocol_begin(), + E = OID->protocol_end(); P != E; ++P) + PushProtocolProperties(PropertySet, Properties, Container, (*P), ObjCTypes); // Return null for empty list. if (Properties.empty()) @@ -2507,8 +2541,11 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // through finally. CGF.PushCleanupBlock(FinallyBlock); - CGF.ObjCEHValueStack.push_back(0); - + if (CGF.ObjCEHValueStack.empty()) + CGF.ObjCEHValueStack.push_back(0); + // If This is a nested @try, caught exception is that of enclosing @try. + else + CGF.ObjCEHValueStack.push_back(CGF.ObjCEHValueStack.back()); // Allocate memory for the exception data and rethrow pointer. llvm::Value *ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy, "exceptiondata.ptr"); @@ -4134,23 +4171,19 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { "\01L_OBJC_LABEL_CLASS_$", "__DATA, __objc_classlist, regular, no_dead_strip"); - bool hasWeakImport = false; for (unsigned i = 0; i < DefinedClasses.size(); i++) { llvm::GlobalValue *IMPLGV = DefinedClasses[i]; if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage) continue; IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage); - hasWeakImport = true; } - if (hasWeakImport) { - for (unsigned i = 0; i < DefinedMetaClasses.size(); i++) { - llvm::GlobalValue *IMPLGV = DefinedMetaClasses[i]; - if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage) - continue; - IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage); - } - } + for (unsigned i = 0; i < DefinedMetaClasses.size(); i++) { + llvm::GlobalValue *IMPLGV = DefinedMetaClasses[i]; + if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage) + continue; + IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage); + } AddModuleClassList(DefinedNonLazyClasses, "\01L_OBJC_LABEL_NONLAZY_CLASS_$", @@ -4437,9 +4470,12 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { while (const ObjCInterfaceDecl *Super = Root->getSuperClass()) Root = Super; IsAGV = GetClassGlobal(ObjCMetaClassName + Root->getNameAsString()); + if (Root->hasAttr<WeakImportAttr>()) + IsAGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); // work on super class metadata symbol. std::string SuperClassName = - ObjCMetaClassName + ID->getClassInterface()->getSuperClass()->getNameAsString(); + ObjCMetaClassName + + ID->getClassInterface()->getSuperClass()->getNameAsString(); SuperClassGV = GetClassGlobal(SuperClassName); if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>()) SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRTTI.cpp index 43fcb31..02de00e 100644 --- a/lib/CodeGen/CGRtti.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -1,4 +1,4 @@ -//===--- CGCXXRtti.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===// +//===--- CGCXXRTTI.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===// // // The LLVM Compiler Infrastructure // @@ -17,14 +17,35 @@ using namespace clang; using namespace CodeGen; -class RttiBuilder { +namespace { +class RTTIBuilder { CodeGenModule &CGM; // Per-module state. llvm::LLVMContext &VMContext; const llvm::Type *Int8PtrTy; llvm::SmallSet<const CXXRecordDecl *, 16> SeenVBase; llvm::SmallSet<const CXXRecordDecl *, 32> SeenBase; + + // Type info flags. + enum { + /// TI_Const - Type has const qualifier. + TI_Const = 0x1, + + /// TI_Volatile - Type has volatile qualifier. + TI_Volatile = 0x2, + + /// TI_Restrict - Type has restrict qualifier. + TI_Restrict = 0x4, + + /// TI_Incomplete - Type is incomplete. + TI_Incomplete = 0x8, + + /// TI_ContainingClassIncomplete - Containing class is incomplete. + /// (in pointer to member). + TI_ContainingClassIncomplete = 0x10 + }; + public: - RttiBuilder(CodeGenModule &cgm) + RTTIBuilder(CodeGenModule &cgm) : CGM(cgm), VMContext(cgm.getModule().getContext()), Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { } @@ -47,27 +68,37 @@ public: return llvm::ConstantExpr::getBitCast(C, Int8PtrTy); } + // FIXME: This should be removed, and clients should pass in the linkage + // directly instead. + static inline llvm::GlobalVariable::LinkageTypes + GetLinkageFromExternFlag(bool Extern) { + if (Extern) + return llvm::GlobalValue::WeakODRLinkage; + + return llvm::GlobalValue::InternalLinkage; + } + + // FIXME: This should be removed, and clients should pass in the linkage + // directly instead. llvm::Constant *BuildName(QualType Ty, bool Hidden, bool Extern) { + return BuildName(Ty, Hidden, GetLinkageFromExternFlag(Extern)); + } + + llvm::Constant *BuildName(QualType Ty, bool Hidden, + llvm::GlobalVariable::LinkageTypes Linkage) { llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRttiName(Ty, OutName); + CGM.getMangleContext().mangleCXXRTTIName(Ty, OutName); llvm::StringRef Name = OutName.str(); - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::LinkOnceODRLinkage; - if (!Extern) - linktype = llvm::GlobalValue::InternalLinkage; - - llvm::GlobalVariable *GV; - GV = CGM.getModule().getGlobalVariable(Name); - if (GV && !GV->isDeclaration()) - return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); + llvm::GlobalVariable *OGV = CGM.getModule().getGlobalVariable(Name); + if (OGV && !OGV->isDeclaration()) + return llvm::ConstantExpr::getBitCast(OGV, Int8PtrTy); - llvm::Constant *C; - C = llvm::ConstantArray::get(VMContext, Name.substr(4)); + llvm::Constant *C = llvm::ConstantArray::get(VMContext, Name.substr(4)); - llvm::GlobalVariable *OGV = GV; - GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, linktype, - C, Name); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, Linkage, + C, Name); if (OGV) { GV->takeName(OGV); llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV, @@ -94,11 +125,8 @@ public: llvm::Constant *BuildTypeRef(QualType Ty) { llvm::Constant *C; - if (!CGM.getContext().getLangOptions().Rtti) - return llvm::Constant::getNullValue(Int8PtrTy); - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRtti(Ty, OutName); + CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); C = CGM.getModule().getGlobalVariable(Name); @@ -158,19 +186,15 @@ public: return true; } - llvm::Constant *finish(std::vector<llvm::Constant *> &info, + llvm::Constant *finish(llvm::Constant *const *Values, unsigned NumValues, llvm::GlobalVariable *GV, - llvm::StringRef Name, bool Hidden, bool Extern) { - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::LinkOnceODRLinkage; - if (!Extern) - linktype = llvm::GlobalValue::InternalLinkage; - - llvm::Constant *C; - C = llvm::ConstantStruct::get(VMContext, &info[0], info.size(), false); + llvm::StringRef Name, bool Hidden, + llvm::GlobalVariable::LinkageTypes Linkage) { + llvm::Constant *C = + llvm::ConstantStruct::get(VMContext, Values, NumValues, /*Packed=*/false); llvm::GlobalVariable *OGV = GV; - GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, linktype, + GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, Linkage, C, Name); if (OGV) { GV->takeName(OGV); @@ -185,14 +209,16 @@ public: } - llvm::Constant *Buildclass_type_info(const CXXRecordDecl *RD) { - if (!CGM.getContext().getLangOptions().Rtti) - return llvm::Constant::getNullValue(Int8PtrTy); - + llvm::Constant * + Buildclass_type_info(const CXXRecordDecl *RD, + llvm::GlobalVariable::LinkageTypes Linkage) { + std::vector<llvm::Constant *> info; + assert(info.empty() && "Info vector must be empty!"); + llvm::Constant *C; llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRtti(CGM.getContext().getTagDeclType(RD), + CGM.getMangleContext().mangleCXXRTTI(CGM.getContext().getTagDeclType(RD), OutName); llvm::StringRef Name = OutName.str(); @@ -201,10 +227,11 @@ public: if (GV && !GV->isDeclaration()) return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); - std::vector<llvm::Constant *> info; - + // If we're in an anonymous namespace, then we always want internal linkage. + if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) + Linkage = llvm::GlobalVariable::InternalLinkage; + bool Hidden = CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden; - bool Extern = !RD->isInAnonymousNamespace(); bool simple = false; if (RD->getNumBases() == 0) @@ -216,7 +243,7 @@ public: C = BuildVtableRef("_ZTVN10__cxxabiv121__vmi_class_type_infoE"); info.push_back(C); info.push_back(BuildName(CGM.getContext().getTagDeclType(RD), Hidden, - Extern)); + Linkage)); // If we have no bases, there are no more fields. if (RD->getNumBases()) { @@ -230,7 +257,7 @@ public: e = RD->bases_end(); i != e; ++i) { const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - info.push_back(CGM.GenerateRttiRef(Base)); + info.push_back(CGM.GetAddrOfRTTI(Base)); if (simple) break; int64_t offset; @@ -249,12 +276,12 @@ public: } } - return finish(info, GV, Name, Hidden, Extern); + return finish(&info[0], info.size(), GV, Name, Hidden, Linkage); } /// - BuildFlags - Build a __flags value for __pbase_type_info. - llvm::Constant *BuildInt(int f) { - return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), f); + llvm::Constant *BuildInt(unsigned n) { + return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), n); } bool DecideExtern(QualType Ty) { @@ -266,7 +293,7 @@ public: return DecideExtern(PT->getPointeeType()); if (const RecordType *RT = Ty->getAs<RecordType>()) if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) - return !RD->isInAnonymousNamespace(); + return !RD->isInAnonymousNamespace() && RD->hasLinkage(); return true; } @@ -284,10 +311,13 @@ public: } llvm::Constant *BuildPointerType(QualType Ty) { + std::vector<llvm::Constant *> info; + assert(info.empty() && "Info vector must be empty!"); + llvm::Constant *C; llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRtti(Ty, OutName); + CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *GV; @@ -295,52 +325,58 @@ public: if (GV && !GV->isDeclaration()) return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); - std::vector<llvm::Constant *> info; - bool Extern = DecideExtern(Ty); bool Hidden = DecideHidden(Ty); - QualType PTy = Ty->getPointeeType(); - QualType BTy; - bool PtrMem = false; - if (const MemberPointerType *MPT = dyn_cast<MemberPointerType>(Ty)) { - PtrMem = true; - BTy = QualType(MPT->getClass(), 0); - PTy = MPT->getPointeeType(); - } + const MemberPointerType *PtrMemTy = dyn_cast<MemberPointerType>(Ty); + QualType PointeeTy; + + if (PtrMemTy) + PointeeTy = PtrMemTy->getPointeeType(); + else + PointeeTy = Ty->getPointeeType(); - if (PtrMem) + if (PtrMemTy) C = BuildVtableRef("_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"); else C = BuildVtableRef("_ZTVN10__cxxabiv119__pointer_type_infoE"); + info.push_back(C); info.push_back(BuildName(Ty, Hidden, Extern)); - Qualifiers Q = PTy.getQualifiers(); - PTy = CGM.getContext().getCanonicalType(PTy).getUnqualifiedType(); - int flags = 0; - flags += Q.hasConst() ? 0x1 : 0; - flags += Q.hasVolatile() ? 0x2 : 0; - flags += Q.hasRestrict() ? 0x4 : 0; - flags += Ty.getTypePtr()->isIncompleteType() ? 0x8 : 0; - if (PtrMem && BTy.getTypePtr()->isIncompleteType()) - flags += 0x10; - - info.push_back(BuildInt(flags)); + Qualifiers Q = PointeeTy.getQualifiers(); + + PointeeTy = + CGM.getContext().getCanonicalType(PointeeTy).getUnqualifiedType(); + + unsigned Flags = 0; + if (Q.hasConst()) + Flags |= TI_Const; + if (Q.hasVolatile()) + Flags |= TI_Volatile; + if (Q.hasRestrict()) + Flags |= TI_Restrict; + + if (Ty->isIncompleteType()) + Flags |= TI_Incomplete; + + if (PtrMemTy && PtrMemTy->getClass()->isIncompleteType()) + Flags |= TI_ContainingClassIncomplete; + + info.push_back(BuildInt(Flags)); info.push_back(BuildInt(0)); - info.push_back(BuildType(PTy)); + info.push_back(BuildType(PointeeTy)); - if (PtrMem) - info.push_back(BuildType(BTy)); + if (PtrMemTy) + info.push_back(BuildType(QualType(PtrMemTy->getClass(), 0))); // We always generate these as hidden, only the name isn't hidden. - return finish(info, GV, Name, true, Extern); + return finish(&info[0], info.size(), GV, Name, /*Hidden=*/true, + GetLinkageFromExternFlag(Extern)); } llvm::Constant *BuildSimpleType(QualType Ty, const char *vtbl) { - llvm::Constant *C; - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRtti(Ty, OutName); + CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *GV; @@ -348,26 +384,26 @@ public: if (GV && !GV->isDeclaration()) return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); - std::vector<llvm::Constant *> info; - bool Extern = DecideExtern(Ty); bool Hidden = DecideHidden(Ty); - C = BuildVtableRef(vtbl); - info.push_back(C); - info.push_back(BuildName(Ty, Hidden, Extern)); - + llvm::Constant *Info[] = { + BuildVtableRef(vtbl), BuildName(Ty, Hidden, Extern) + }; + // We always generate these as hidden, only the name isn't hidden. - return finish(info, GV, Name, true, Extern); + return finish(&Info[0], llvm::array_lengthof(Info), GV, Name, + /*Hidden=*/true, GetLinkageFromExternFlag(Extern)); } + /// BuildType - Builds the type info for the given type. llvm::Constant *BuildType(QualType Ty) { const clang::Type &Type = *CGM.getContext().getCanonicalType(Ty).getTypePtr(); if (const RecordType *RT = Ty.getTypePtr()->getAs<RecordType>()) if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl())) - return Buildclass_type_info(RD); + return BuildClassTypeInfo(RD); switch (Type.getTypeClass()) { default: { @@ -405,22 +441,65 @@ public: return BuildSimpleType(Ty, "_ZTVN10__cxxabiv116__enum_type_infoE"); } } + + /// BuildClassTypeInfo - Builds the class type info (or a reference to it) + /// for the given record decl. + llvm::Constant *BuildClassTypeInfo(const CXXRecordDecl *RD) { + const CXXMethodDecl *KeyFunction = 0; + + if (RD->isDynamicClass()) + KeyFunction = CGM.getContext().getKeyFunction(RD); + + if (KeyFunction) { + // If the key function is defined in this translation unit, then the RTTI + // related constants should also be emitted here, with external linkage. + if (KeyFunction->getBody()) + return Buildclass_type_info(RD, llvm::GlobalValue::ExternalLinkage); + + // Otherwise, we just want a reference to the type info. + return Buildclass_type_infoRef(RD); + } + + // If there is no key function (or if the record doesn't have any virtual + // member functions or virtual bases), emit the type info with weak_odr + // linkage. + return Buildclass_type_info(RD, llvm::GlobalValue::WeakODRLinkage); + } }; +} + +llvm::Constant *CodeGenModule::GetAddrOfRTTI(const CXXRecordDecl *RD) { + if (!getContext().getLangOptions().RTTI) { + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + return llvm::Constant::getNullValue(Int8PtrTy); + } + + return RTTIBuilder(*this).BuildClassTypeInfo(RD); +} + +llvm::Constant *CodeGenModule::GetAddrOfRTTI(QualType Ty) { + if (!getContext().getLangOptions().RTTI) { + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + return llvm::Constant::getNullValue(Int8PtrTy); + } + + return RTTIBuilder(*this).BuildType(Ty); +} -llvm::Constant *CodeGenModule::GenerateRttiRef(const CXXRecordDecl *RD) { - RttiBuilder b(*this); +llvm::Constant *CodeGenModule::GenerateRTTIRef(const CXXRecordDecl *RD) { + RTTIBuilder b(*this); return b.Buildclass_type_infoRef(RD); } -llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) { - RttiBuilder b(*this); +llvm::Constant *CodeGenModule::GenerateRTTI(const CXXRecordDecl *RD) { + RTTIBuilder b(*this); - return b.Buildclass_type_info(RD); + return b.Buildclass_type_info(RD, llvm::GlobalValue::ExternalLinkage); } -llvm::Constant *CodeGenModule::GenerateRtti(QualType Ty) { - RttiBuilder b(*this); +llvm::Constant *CodeGenModule::GenerateRTTI(QualType Ty) { + RTTIBuilder b(*this); return b.BuildType(Ty); } diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 1a9bc39..31784ed 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -88,8 +88,6 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, AppendBytes(NumBytesToAppend); - AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct, getTypeAlignment(Ty)); - BitsAvailableInLastField = NextFieldOffsetInBytes * 8 - (FieldOffset + FieldSize); } @@ -247,6 +245,14 @@ void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) { uint64_t RecordSizeInBytes = RecordSize / 8; assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); + uint64_t AlignedNextFieldOffset = + llvm::RoundUpToAlignment(NextFieldOffsetInBytes, AlignmentAsLLVMStruct); + + if (AlignedNextFieldOffset == RecordSizeInBytes) { + // We don't need any padding. + return; + } + unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; AppendBytes(NumPadBytes); } diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 715aa4c..5283ed9 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -26,12 +26,23 @@ class VtableBuilder { public: /// Index_t - Vtable index type. typedef uint64_t Index_t; + typedef std::vector<std::pair<GlobalDecl, + std::pair<GlobalDecl, ThunkAdjustment> > > + SavedAdjustmentsVectorTy; private: - std::vector<llvm::Constant *> &methods; - std::vector<llvm::Constant *> submethods; + + // VtableComponents - The components of the vtable being built. + typedef llvm::SmallVector<llvm::Constant *, 64> VtableComponentsVectorTy; + VtableComponentsVectorTy VtableComponents; + + const bool BuildVtable; + llvm::Type *Ptr8Ty; - /// Class - The most derived class that this vtable is being built for. - const CXXRecordDecl *Class; + + /// MostDerivedClass - The most derived class that this vtable is being + /// built for. + const CXXRecordDecl *MostDerivedClass; + /// LayoutClass - The most derived class used for virtual base layout /// information. const CXXRecordDecl *LayoutClass; @@ -45,9 +56,7 @@ private: llvm::Constant *rtti; llvm::LLVMContext &VMContext; CodeGenModule &CGM; // Per-module state. - /// Index - Maps a method decl into a vtable index. Useful for virtual - /// dispatch codegen. - llvm::DenseMap<GlobalDecl, Index_t> Index; + llvm::DenseMap<GlobalDecl, Index_t> VCall; llvm::DenseMap<GlobalDecl, Index_t> VCallOffset; // This is the offset to the nearest virtual base @@ -57,54 +66,93 @@ private: /// PureVirtualFunction - Points to __cxa_pure_virtual. llvm::Constant *PureVirtualFn; - /// Thunk - Represents a single thunk. - struct Thunk { - Thunk() - : Index(0) { } - - Thunk(uint64_t Index, const ThunkAdjustment &Adjustment) - : Index(Index), Adjustment(Adjustment) { } - - /// Index - The index in the vtable. - uint64_t Index; + /// VtableMethods - A data structure for keeping track of methods in a vtable. + /// Can add methods, override methods and iterate in vtable order. + class VtableMethods { + // MethodToIndexMap - Maps from a global decl to the index it has in the + // Methods vector. + llvm::DenseMap<GlobalDecl, uint64_t> MethodToIndexMap; + + /// Methods - The methods, in vtable order. + typedef llvm::SmallVector<GlobalDecl, 16> MethodsVectorTy; + MethodsVectorTy Methods; + MethodsVectorTy OrigMethods; + + public: + /// AddMethod - Add a method to the vtable methods. + void AddMethod(GlobalDecl GD) { + assert(!MethodToIndexMap.count(GD) && + "Method has already been added!"); + + MethodToIndexMap[GD] = Methods.size(); + Methods.push_back(GD); + OrigMethods.push_back(GD); + } - /// Adjustment - The thunk adjustment. - ThunkAdjustment Adjustment; - }; + /// OverrideMethod - Replace a method with another. + void OverrideMethod(GlobalDecl OverriddenGD, GlobalDecl GD) { + llvm::DenseMap<GlobalDecl, uint64_t>::iterator i + = MethodToIndexMap.find(OverriddenGD); + assert(i != MethodToIndexMap.end() && "Did not find entry!"); + + // Get the index of the old decl. + uint64_t Index = i->second; + + // Replace the old decl with the new decl. + Methods[Index] = GD; - /// Thunks - The thunks in a vtable. - typedef llvm::DenseMap<GlobalDecl, Thunk> ThunksMapTy; - ThunksMapTy Thunks; + // And add the new. + MethodToIndexMap[GD] = Index; + } - /// CovariantThunk - Represents a single covariant thunk. - struct CovariantThunk { - CovariantThunk() - : Index(0) { } - - CovariantThunk(uint64_t Index, const ThunkAdjustment &ThisAdjustment, - const ThunkAdjustment &ReturnAdjustment, - CanQualType ReturnType) - : Index(Index), Adjustment(ThisAdjustment, ReturnAdjustment), - ReturnType(ReturnType) { } - - // Index - The index in the vtable. - uint64_t Index; - - /// Adjustment - The covariant thunk adjustment. - CovariantThunkAdjustment Adjustment; + /// getIndex - Gives the index of a passed in GlobalDecl. Returns false if + /// the index couldn't be found. + bool getIndex(GlobalDecl GD, uint64_t &Index) const { + llvm::DenseMap<GlobalDecl, uint64_t>::const_iterator i + = MethodToIndexMap.find(GD); + + if (i == MethodToIndexMap.end()) + return false; + + Index = i->second; + return true; + } + + GlobalDecl getOrigMethod(uint64_t Index) const { + return OrigMethods[Index]; + } + + MethodsVectorTy::size_type size() const { + return Methods.size(); + } + + void clear() { + MethodToIndexMap.clear(); + Methods.clear(); + OrigMethods.clear(); + } - /// ReturnType - The return type of the function. - CanQualType ReturnType; + GlobalDecl operator[](uint64_t Index) const { + return Methods[Index]; + } }; - /// CovariantThunks - The covariant thunks in a vtable. - typedef llvm::DenseMap<GlobalDecl, CovariantThunk> CovariantThunksMapTy; - CovariantThunksMapTy CovariantThunks; + /// Methods - The vtable methods we're currently building. + VtableMethods Methods; + + /// ThisAdjustments - For a given index in the vtable, contains the 'this' + /// pointer adjustment needed for a method. + typedef llvm::DenseMap<uint64_t, ThunkAdjustment> ThisAdjustmentsMapTy; + ThisAdjustmentsMapTy ThisAdjustments; + + SavedAdjustmentsVectorTy SavedAdjustments; + + /// BaseReturnTypes - Contains the base return types of methods who have been + /// overridden with methods whose return types require adjustment. Used for + /// generating covariant thunk information. + typedef llvm::DenseMap<uint64_t, CanQualType> BaseReturnTypesMapTy; + BaseReturnTypesMapTy BaseReturnTypes; - /// PureVirtualMethods - Pure virtual methods. - typedef llvm::DenseSet<GlobalDecl> PureVirtualMethodsSetTy; - PureVirtualMethodsSetTy PureVirtualMethods; - std::vector<Index_t> VCalls; typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t; @@ -143,21 +191,32 @@ private: } public: - VtableBuilder(std::vector<llvm::Constant *> &meth, const CXXRecordDecl *c, - const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm) - : methods(meth), Class(c), LayoutClass(l), LayoutOffset(lo), - BLayout(cgm.getContext().getASTRecordLayout(l)), - rtti(cgm.GenerateRttiRef(c)), VMContext(cgm.getModule().getContext()), - CGM(cgm), PureVirtualFn(0),subAddressPoints(AllocAddressPoint(cgm, l, c)), + VtableBuilder(const CXXRecordDecl *MostDerivedClass, + const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm, + bool build) + : BuildVtable(build), MostDerivedClass(MostDerivedClass), LayoutClass(l), + LayoutOffset(lo), BLayout(cgm.getContext().getASTRecordLayout(l)), + rtti(0), VMContext(cgm.getModule().getContext()),CGM(cgm), + PureVirtualFn(0), + subAddressPoints(AllocAddressPoint(cgm, l, MostDerivedClass)), Extern(!l->isInAnonymousNamespace()), - LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) { + LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) { Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + if (BuildVtable) + rtti = CGM.GetAddrOfRTTI(MostDerivedClass); } - llvm::DenseMap<GlobalDecl, Index_t> &getIndex() { return Index; } + // getVtableComponents - Returns a reference to the vtable components. + const VtableComponentsVectorTy &getVtableComponents() const { + return VtableComponents; + } + llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex() { return VBIndex; } + SavedAdjustmentsVectorTy &getSavedAdjustments() + { return SavedAdjustments; } + llvm::Constant *wrap(Index_t i) { llvm::Constant *m; m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i); @@ -168,8 +227,8 @@ public: return llvm::ConstantExpr::getBitCast(m, Ptr8Ty); } -//#define D1(x) -#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0) +#define D1(x) +//#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0) void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, bool updateVBIndex, Index_t current_vbindex) { @@ -249,7 +308,7 @@ public: qB = qB->getPointeeType(); CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); - if (D != Class) + if (D != MostDerivedClass) return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B); llvm::DenseMap<const CXXRecordDecl *, Index_t>::iterator i; i = VBIndex.find(B); @@ -260,166 +319,19 @@ public: return 0; } - bool OverrideMethod(GlobalDecl GD, llvm::Constant *m, - bool MorallyVirtual, Index_t OverrideOffset, - Index_t Offset, int64_t CurrentVBaseOffset) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - - const bool isPure = MD->isPure(); - typedef CXXMethodDecl::method_iterator meth_iter; - // FIXME: Should OverrideOffset's be Offset? - - // FIXME: Don't like the nested loops. For very large inheritance - // heirarchies we could have a table on the side with the final overridder - // and just replace each instance of an overridden method once. Would be - // nice to measure the cost/benefit on real code. - - for (meth_iter mi = MD->begin_overridden_methods(), - e = MD->end_overridden_methods(); - mi != e; ++mi) { - GlobalDecl OGD; - - const CXXMethodDecl *OMD = *mi; - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD)) - OGD = GlobalDecl(DD, GD.getDtorType()); - else - OGD = OMD; - - llvm::Constant *om; - om = WrapAddrOf(OGD); - om = llvm::ConstantExpr::getBitCast(om, Ptr8Ty); - - for (Index_t i = 0, e = submethods.size(); - i != e; ++i) { - // FIXME: begin_overridden_methods might be too lax, covariance */ - if (submethods[i] != om) - continue; - QualType nc_oret = OMD->getType()->getAs<FunctionType>()->getResultType(); - CanQualType oret = CGM.getContext().getCanonicalType(nc_oret); - QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType(); - CanQualType ret = CGM.getContext().getCanonicalType(nc_ret); - ThunkAdjustment ReturnAdjustment; - if (oret != ret) { - // FIXME: calculate offsets for covariance - CovariantThunksMapTy::iterator i = CovariantThunks.find(OMD); - if (i != CovariantThunks.end()) { - oret = i->second.ReturnType; - CovariantThunks.erase(i); - } - // FIXME: Double check oret - Index_t nv = getNVOffset(oret, ret)/8; - ReturnAdjustment = ThunkAdjustment(nv, getVbaseOffset(oret, ret)); - } - Index[GD] = i; - submethods[i] = m; - if (isPure) - PureVirtualMethods.insert(GD); - PureVirtualMethods.erase(OGD); - Thunks.erase(OGD); - if (MorallyVirtual || VCall.count(OGD)) { - Index_t &idx = VCall[OGD]; - if (idx == 0) { - NonVirtualOffset[GD] = -OverrideOffset/8 + CurrentVBaseOffset/8; - VCallOffset[GD] = OverrideOffset/8; - idx = VCalls.size()+1; - VCalls.push_back(0); - D1(printf(" vcall for %s at %d with delta %d most derived %s\n", - MD->getNameAsString().c_str(), (int)-idx-3, - (int)VCalls[idx-1], Class->getNameAsCString())); - } else { - NonVirtualOffset[GD] = NonVirtualOffset[OGD]; - VCallOffset[GD] = VCallOffset[OGD]; - VCalls[idx-1] = -VCallOffset[OGD] + OverrideOffset/8; - D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n", - MD->getNameAsString().c_str(), (int)-idx-3, - (int)VCalls[idx-1], Class->getNameAsCString())); - } - VCall[GD] = idx; - int64_t NonVirtualAdjustment = NonVirtualOffset[GD]; - int64_t VirtualAdjustment = - -((idx + extra + 2) * LLVMPointerWidth / 8); - - // Optimize out virtual adjustments of 0. - if (VCalls[idx-1] == 0) - VirtualAdjustment = 0; - - ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, - VirtualAdjustment); - - // FIXME: Do we always have to build a covariant thunk to save oret, - // which is the containing virtual base class? - if (!ReturnAdjustment.isEmpty()) { - CovariantThunks[GD] = - CovariantThunk(i, ThisAdjustment, ReturnAdjustment, oret); - } else if (!isPure && !ThisAdjustment.isEmpty()) - Thunks[GD] = Thunk(i, ThisAdjustment); - return true; - } - - // FIXME: finish off - int64_t NonVirtualAdjustment = VCallOffset[OGD] - OverrideOffset/8; - - if (NonVirtualAdjustment || !ReturnAdjustment.isEmpty()) { - ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0); - - if (!ReturnAdjustment.isEmpty()) { - CovariantThunks[GD] = - CovariantThunk(i, ThisAdjustment, ReturnAdjustment, oret); - } else if (!isPure) - Thunks[GD] = Thunk(i, ThisAdjustment); - } - return true; - } - } - - return false; - } - - void InstallThunks() { - for (ThunksMapTy::const_iterator i = Thunks.begin(), e = Thunks.end(); - i != e; ++i) { - GlobalDecl GD = i->first; - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - assert(!MD->isPure() && "Can't thunk pure virtual methods!"); - - const Thunk& Thunk = i->second; - assert(Thunk.Index == Index[GD] && "Thunk index mismatch!"); - - submethods[Thunk.Index] = CGM.BuildThunk(MD, Extern, Thunk.Adjustment); - } - Thunks.clear(); - - for (CovariantThunksMapTy::const_iterator i = CovariantThunks.begin(), - e = CovariantThunks.end(); i != e; ++i) { - GlobalDecl GD = i->first; - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - if (MD->isPure()) - continue; - - const CovariantThunk &Thunk = i->second; - assert(Thunk.Index == Index[GD] && "Thunk index mismatch!"); - submethods[Thunk.Index] = - CGM.BuildCovariantThunk(MD, Extern, Thunk.Adjustment); - } - CovariantThunks.clear(); - - for (PureVirtualMethodsSetTy::iterator i = PureVirtualMethods.begin(), - e = PureVirtualMethods.end(); i != e; ++i) { - GlobalDecl GD = *i; - submethods[Index[GD]] = getPureVirtualFn(); - } - PureVirtualMethods.clear(); - } + bool OverrideMethod(GlobalDecl GD, bool MorallyVirtual, + Index_t OverrideOffset, Index_t Offset, + int64_t CurrentVBaseOffset); + /// AppendMethods - Append the current methods to the vtable. + void AppendMethodsToVtable(); + llvm::Constant *WrapAddrOf(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) - return wrap(CGM.GetAddrOfCXXDestructor(Dtor, GD.getDtorType())); - const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD); - return wrap(CGM.GetAddrOfFunction(MD, Ty)); + return wrap(CGM.GetAddrOfFunction(GD, Ty)); } void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset, @@ -438,15 +350,15 @@ public: if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { // Override both the complete and the deleting destructor. GlobalDecl CompDtor(DD, Dtor_Complete); - OverrideMethod(CompDtor, WrapAddrOf(CompDtor), MorallyVirtual, - OverrideOffset, Offset, CurrentVBaseOffset); - + OverrideMethod(CompDtor, MorallyVirtual, OverrideOffset, Offset, + CurrentVBaseOffset); + GlobalDecl DeletingDtor(DD, Dtor_Deleting); - OverrideMethod(DeletingDtor, WrapAddrOf(DeletingDtor), MorallyVirtual, - OverrideOffset, Offset, CurrentVBaseOffset); + OverrideMethod(DeletingDtor, MorallyVirtual, OverrideOffset, Offset, + CurrentVBaseOffset); } else { - OverrideMethod(MD, WrapAddrOf(MD), MorallyVirtual, OverrideOffset, - Offset, CurrentVBaseOffset); + OverrideMethod(MD, MorallyVirtual, OverrideOffset, Offset, + CurrentVBaseOffset); } } } @@ -454,24 +366,20 @@ public: void AddMethod(const GlobalDecl GD, bool MorallyVirtual, Index_t Offset, int64_t CurrentVBaseOffset) { - llvm::Constant *m = WrapAddrOf(GD); - // If we can find a previously allocated slot for this, reuse it. - if (OverrideMethod(GD, m, MorallyVirtual, Offset, Offset, + if (OverrideMethod(GD, MorallyVirtual, Offset, Offset, CurrentVBaseOffset)) return; - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - - // else allocate a new slot. - Index[GD] = submethods.size(); - submethods.push_back(m); + // We didn't find an entry in the vtable that we could use, add a new + // entry. + Methods.AddMethod(GD); + D1(printf(" vfn for %s at %d\n", MD->getNameAsString().c_str(), (int)Index[GD])); - if (MD->isPure()) - PureVirtualMethods.insert(GD); + + VCallOffset[GD] = Offset/8; if (MorallyVirtual) { - VCallOffset[GD] = Offset/8; Index_t &idx = VCall[GD]; // Allocate the first one, after that, we reuse the previous one. if (idx == 0) { @@ -530,16 +438,19 @@ public: #define D(X) void insertVCalls(int InsertionPoint) { - llvm::Constant *e = 0; D1(printf("============= combining vbase/vcall\n")); D(VCalls.insert(VCalls.begin(), 673)); D(VCalls.push_back(672)); - methods.insert(methods.begin() + InsertionPoint, VCalls.size(), e); - // The vcalls come first... - for (std::vector<Index_t>::reverse_iterator i = VCalls.rbegin(), - e = VCalls.rend(); - i != e; ++i) - methods[InsertionPoint++] = wrap((0?600:0) + *i); + + VtableComponents.insert(VtableComponents.begin() + InsertionPoint, + VCalls.size(), 0); + if (BuildVtable) { + // The vcalls come first... + for (std::vector<Index_t>::reverse_iterator i = VCalls.rbegin(), + e = VCalls.rend(); + i != e; ++i) + VtableComponents[InsertionPoint++] = wrap((0?600:0) + *i); + } VCalls.clear(); VCall.clear(); } @@ -570,11 +481,13 @@ public: } - Index_t end(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, - const CXXRecordDecl *PrimaryBase, bool PrimaryBaseWasVirtual, - bool MorallyVirtual, int64_t Offset, bool ForVirtualBase, - int64_t CurrentVBaseOffset, - Path_t *Path) { + Index_t FinishGenerateVtable(const CXXRecordDecl *RD, + const ASTRecordLayout &Layout, + const CXXRecordDecl *PrimaryBase, + bool PrimaryBaseWasVirtual, + bool MorallyVirtual, int64_t Offset, + bool ForVirtualBase, int64_t CurrentVBaseOffset, + Path_t *Path) { bool alloc = false; if (Path == 0) { alloc = true; @@ -584,21 +497,22 @@ public: StartNewTable(); extra = 0; bool DeferVCalls = MorallyVirtual || ForVirtualBase; - int VCallInsertionPoint = methods.size(); + int VCallInsertionPoint = VtableComponents.size(); if (!DeferVCalls) { insertVCalls(VCallInsertionPoint); } else // FIXME: just for extra, or for all uses of VCalls.size post this? extra = -VCalls.size(); - methods.push_back(wrap(-((Offset-LayoutOffset)/8))); - methods.push_back(rtti); - Index_t AddressPoint = methods.size(); + // Add the offset to top. + VtableComponents.push_back(BuildVtable ? wrap(-((Offset-LayoutOffset)/8)) : 0); + + // Add the RTTI information. + VtableComponents.push_back(rtti); + + Index_t AddressPoint = VtableComponents.size(); - InstallThunks(); - D1(printf("============= combining methods\n")); - methods.insert(methods.end(), submethods.begin(), submethods.end()); - submethods.clear(); + AppendMethodsToVtable(); // and then the non-virtual bases. NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, @@ -635,17 +549,11 @@ public: const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); // vtables are composed from the chain of primaries. - if (PrimaryBase) { + if (PrimaryBase && !PrimaryBaseWasVirtual) { D1(printf(" doing primaries for %s most derived %s\n", RD->getNameAsCString(), Class->getNameAsCString())); - - int BaseCurrentVBaseOffset = CurrentVBaseOffset; - if (PrimaryBaseWasVirtual) - BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase); - - if (!PrimaryBaseWasVirtual) - Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, - updateVBIndex, current_vbindex, BaseCurrentVBaseOffset); + Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, + updateVBIndex, current_vbindex, CurrentVBaseOffset); } D1(printf(" doing vcall entries for %s most derived %s\n", @@ -702,7 +610,8 @@ public: // Construction vtable don't need parts that have no virtual bases and // aren't morally virtual. - if ((LayoutClass != Class) && RD->getNumVBases() == 0 && !MorallyVirtual) + if ((LayoutClass != MostDerivedClass) && + RD->getNumVBases() == 0 && !MorallyVirtual) return 0; const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); @@ -722,8 +631,9 @@ public: if (Path) OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset); - return end(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual, - Offset, ForVirtualBase, CurrentVBaseOffset, Path); + return FinishGenerateVtable(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, + MorallyVirtual, Offset, ForVirtualBase, + CurrentVBaseOffset, Path); } void GenerateVtableForVBases(const CXXRecordDecl *RD, @@ -770,8 +680,7 @@ public: delete Path; } }; - -} +} // end anonymous namespace /// TypeConversionRequiresAdjustment - Returns whether conversion from a /// derived type to a base type requires adjustment. @@ -790,18 +699,18 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx, // If we found a virtual base we always want to require adjustment. if (Paths.getDetectedVirtual()) return true; - + const CXXBasePath &Path = Paths.front(); for (size_t Start = 0, End = Path.size(); Start != End; ++Start) { const CXXBasePathElement &Element = Path[Start]; - + // Check the base class offset. const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Element.Class); const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>(); const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl()); - + if (Layout.getBaseClassOffset(Base) != 0) { // This requires an adjustment. return true; @@ -825,7 +734,7 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx, // No adjustment needed. return false; } - + if (const ReferenceType *RT = dyn_cast<ReferenceType>(CanDerivedType)) { CanDerivedType = RT->getPointeeType(); CanBaseType = cast<ReferenceType>(CanBaseType)->getPointeeType(); @@ -835,21 +744,190 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx, } else { assert(false && "Unexpected return type!"); } - + if (CanDerivedType == CanBaseType) { // No adjustment needed. return false; } const CXXRecordDecl *DerivedDecl = - cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl()); - + cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl()); + const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl()); - + cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl()); + return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl); } +bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, + Index_t OverrideOffset, Index_t Offset, + int64_t CurrentVBaseOffset) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + const bool isPure = MD->isPure(); + + // FIXME: Should OverrideOffset's be Offset? + + for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(), + e = MD->end_overridden_methods(); mi != e; ++mi) { + GlobalDecl OGD; + + const CXXMethodDecl *OMD = *mi; + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD)) + OGD = GlobalDecl(DD, GD.getDtorType()); + else + OGD = OMD; + + // Check whether this is the method being overridden in this section of + // the vtable. + uint64_t Index; + if (!Methods.getIndex(OGD, Index)) + continue; + + // Get the original method, which we should be computing thunks, etc, + // against. + OGD = Methods.getOrigMethod(Index); + OMD = cast<CXXMethodDecl>(OGD.getDecl()); + + QualType ReturnType = + MD->getType()->getAs<FunctionType>()->getResultType(); + QualType OverriddenReturnType = + OMD->getType()->getAs<FunctionType>()->getResultType(); + + // Check if we need a return type adjustment. + if (TypeConversionRequiresAdjustment(CGM.getContext(), ReturnType, + OverriddenReturnType)) { + CanQualType &BaseReturnType = BaseReturnTypes[Index]; + + // Insert the base return type. + if (BaseReturnType.isNull()) + BaseReturnType = + CGM.getContext().getCanonicalType(OverriddenReturnType); + } + + Methods.OverrideMethod(OGD, GD); + + ThisAdjustments.erase(Index); + if (MorallyVirtual || VCall.count(OGD)) { + Index_t &idx = VCall[OGD]; + if (idx == 0) { + NonVirtualOffset[GD] = -OverrideOffset/8 + CurrentVBaseOffset/8; + VCallOffset[GD] = OverrideOffset/8; + idx = VCalls.size()+1; + VCalls.push_back(0); + D1(printf(" vcall for %s at %d with delta %d most derived %s\n", + MD->getNameAsString().c_str(), (int)-idx-3, + (int)VCalls[idx-1], Class->getNameAsCString())); + } else { + NonVirtualOffset[GD] = NonVirtualOffset[OGD]; + VCallOffset[GD] = VCallOffset[OGD]; + VCalls[idx-1] = -VCallOffset[OGD] + OverrideOffset/8; + D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n", + MD->getNameAsString().c_str(), (int)-idx-3, + (int)VCalls[idx-1], Class->getNameAsCString())); + } + VCall[GD] = idx; + int64_t NonVirtualAdjustment = NonVirtualOffset[GD]; + int64_t VirtualAdjustment = + -((idx + extra + 2) * LLVMPointerWidth / 8); + + // Optimize out virtual adjustments of 0. + if (VCalls[idx-1] == 0) + VirtualAdjustment = 0; + + ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, + VirtualAdjustment); + + if (!isPure && !ThisAdjustment.isEmpty()) { + ThisAdjustments[Index] = ThisAdjustment; + SavedAdjustments.push_back( + std::make_pair(GD, std::make_pair(OGD, ThisAdjustment))); + } + return true; + } + + int64_t NonVirtualAdjustment = -VCallOffset[OGD] + OverrideOffset/8; + + if (NonVirtualAdjustment) { + ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0); + + if (!isPure) { + ThisAdjustments[Index] = ThisAdjustment; + SavedAdjustments.push_back( + std::make_pair(GD, std::make_pair(OGD, ThisAdjustment))); + } + } + return true; + } + + return false; +} + +void VtableBuilder::AppendMethodsToVtable() { + if (!BuildVtable) { + VtableComponents.insert(VtableComponents.end(), Methods.size(), + (llvm::Constant *)0); + ThisAdjustments.clear(); + BaseReturnTypes.clear(); + Methods.clear(); + return; + } + + // Reserve room in the vtable for our new methods. + VtableComponents.reserve(VtableComponents.size() + Methods.size()); + + for (unsigned i = 0, e = Methods.size(); i != e; ++i) { + GlobalDecl GD = Methods[i]; + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + // Get the 'this' pointer adjustment. + ThunkAdjustment ThisAdjustment = ThisAdjustments.lookup(i); + + // Construct the return type adjustment. + ThunkAdjustment ReturnAdjustment; + + QualType BaseReturnType = BaseReturnTypes.lookup(i); + if (!BaseReturnType.isNull() && !MD->isPure()) { + QualType DerivedType = + MD->getType()->getAs<FunctionType>()->getResultType(); + + int64_t NonVirtualAdjustment = + getNVOffset(BaseReturnType, DerivedType) / 8; + + int64_t VirtualAdjustment = + getVbaseOffset(BaseReturnType, DerivedType); + + ReturnAdjustment = ThunkAdjustment(NonVirtualAdjustment, + VirtualAdjustment); + } + + llvm::Constant *Method = 0; + if (!ReturnAdjustment.isEmpty()) { + // Build a covariant thunk. + CovariantThunkAdjustment Adjustment(ThisAdjustment, ReturnAdjustment); + Method = wrap(CGM.GetAddrOfCovariantThunk(GD, Adjustment)); + } else if (!ThisAdjustment.isEmpty()) { + // Build a "regular" thunk. + Method = wrap(CGM.GetAddrOfThunk(GD, ThisAdjustment)); + } else if (MD->isPure()) { + // We have a pure virtual method. + Method = getPureVirtualFn(); + } else { + // We have a good old regular method. + Method = WrapAddrOf(GD); + } + + // Add the method to the vtable. + VtableComponents.push_back(Method); + } + + + ThisAdjustments.clear(); + BaseReturnTypes.clear(); + + Methods.clear(); +} + void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // Itanium C++ ABI 2.5.2: @@ -874,7 +952,15 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // we need to start counting at the end of the primary base's vtable. CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase); } - + + // Collect all the primary bases, so we can check whether methods override + // a method from the base. + llvm::SmallPtrSet<const CXXRecordDecl *, 5> PrimaryBases; + for (ASTRecordLayout::primary_base_info_iterator + I = Layout.primary_base_begin(), E = Layout.primary_base_end(); + I != E; ++I) + PrimaryBases.insert((*I).getBase()); + const CXXDestructorDecl *ImplicitVirtualDtor = 0; for (CXXRecordDecl::method_iterator i = RD->method_begin(), @@ -895,7 +981,7 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { assert(OverriddenMD->isCanonicalDecl() && "Should have the canonical decl of the overridden RD!"); - if (OverriddenRD == PrimaryBase) { + if (PrimaryBases.count(OverriddenRD)) { // Check if converting from the return type of the method to the // return type of the overridden method requires conversion. QualType ReturnType = @@ -993,6 +1079,33 @@ uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) { return I->second; } +CGVtableInfo::AdjustmentVectorTy* +CGVtableInfo::getAdjustments(GlobalDecl GD) { + SavedAdjustmentsTy::iterator I = SavedAdjustments.find(GD); + if (I != SavedAdjustments.end()) + return &I->second; + + const CXXRecordDecl *RD = cast<CXXRecordDecl>(GD.getDecl()->getDeclContext()); + if (!SavedAdjustmentRecords.insert(RD).second) + return 0; + + VtableBuilder b(RD, RD, 0, CGM, false); + D1(printf("vtable %s\n", RD->getNameAsCString())); + b.GenerateVtableForBase(RD); + b.GenerateVtableForVBases(RD); + + for (VtableBuilder::SavedAdjustmentsVectorTy::iterator + i = b.getSavedAdjustments().begin(), + e = b.getSavedAdjustments().end(); i != e; i++) + SavedAdjustments[i->first].push_back(i->second); + + I = SavedAdjustments.find(GD); + if (I != SavedAdjustments.end()) + return &I->second; + + return 0; +} + int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, const CXXRecordDecl *VBase) { ClassPairTy ClassPair(RD, VBase); @@ -1002,10 +1115,9 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, if (I != VirtualBaseClassIndicies.end()) return I->second; - std::vector<llvm::Constant *> methods; // FIXME: This seems expensive. Can we do a partial job to get // just this data. - VtableBuilder b(methods, RD, RD, 0, CGM); + VtableBuilder b(RD, RD, 0, CGM, false); D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -1024,30 +1136,38 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, return I->second; } -llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, - uint64_t Offset) { +uint64_t CGVtableInfo::getVtableAddressPoint(const CXXRecordDecl *RD) { + uint64_t AddressPoint = + (*(*(CGM.AddressPoints[RD]))[RD])[std::make_pair(RD, 0)]; + + return AddressPoint; +} + +llvm::GlobalVariable * +CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, + bool GenerateDefinition, + const CXXRecordDecl *LayoutClass, + const CXXRecordDecl *RD, uint64_t Offset) { llvm::SmallString<256> OutName; if (LayoutClass != RD) - getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset/8, RD, OutName); + CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8, + RD, OutName); else - getMangleContext().mangleCXXVtable(RD, OutName); + CGM.getMangleContext().mangleCXXVtable(RD, OutName); llvm::StringRef Name = OutName.str(); - std::vector<llvm::Constant *> methods; - llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); int64_t AddressPoint; - llvm::GlobalVariable *GV = getModule().getGlobalVariable(Name); - if (GV && AddressPoints[LayoutClass] && !GV->isDeclaration()) { - AddressPoint=(*(*(AddressPoints[LayoutClass]))[RD])[std::make_pair(RD, + llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); + if (GV && CGM.AddressPoints[LayoutClass] && !GV->isDeclaration()) { + AddressPoint=(*(*(CGM.AddressPoints[LayoutClass]))[RD])[std::make_pair(RD, Offset)]; // FIXME: We can never have 0 address point. Do this for now so gepping // retains the same structure. Later, we'll just assert. if (AddressPoint == 0) AddressPoint = 1; } else { - VtableBuilder b(methods, RD, LayoutClass, Offset, *this); + VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition); D1(printf("vtable %s\n", RD->getNameAsCString())); // First comes the vtables for all the non-virtual bases... @@ -1056,59 +1176,34 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass, // then the vtables for all the virtual bases. b.GenerateVtableForVBases(RD, Offset); - bool CreateDefinition = true; - if (LayoutClass != RD) - CreateDefinition = true; - else { - const ASTRecordLayout &Layout = - getContext().getASTRecordLayout(LayoutClass); - - if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) { - if (!KeyFunction->getBody()) { - // If there is a KeyFunction, and it isn't defined, just build a - // reference to the vtable. - CreateDefinition = false; - } - } - } + llvm::Constant *Init = 0; + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + llvm::ArrayType *ArrayType = + llvm::ArrayType::get(Int8PtrTy, b.getVtableComponents().size()); + + if (GenerateDefinition) + Init = llvm::ConstantArray::get(ArrayType, &b.getVtableComponents()[0], + b.getVtableComponents().size()); - llvm::Constant *C = 0; - llvm::Type *type = Ptr8Ty; - llvm::GlobalVariable::LinkageTypes linktype - = llvm::GlobalValue::ExternalLinkage; - if (CreateDefinition) { - llvm::ArrayType *ntype = llvm::ArrayType::get(Ptr8Ty, methods.size()); - C = llvm::ConstantArray::get(ntype, methods); - linktype = llvm::GlobalValue::LinkOnceODRLinkage; - if (LayoutClass->isInAnonymousNamespace()) - linktype = llvm::GlobalValue::InternalLinkage; - type = ntype; - } llvm::GlobalVariable *OGV = GV; - GV = new llvm::GlobalVariable(getModule(), type, true, linktype, C, Name); + + GV = new llvm::GlobalVariable(CGM.getModule(), ArrayType, + /*isConstant=*/true, Linkage, Init, Name); + CGM.setGlobalVisibility(GV, RD); + if (OGV) { GV->takeName(OGV); - llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV, - OGV->getType()); + llvm::Constant *NewPtr = + llvm::ConstantExpr::getBitCast(GV, OGV->getType()); OGV->replaceAllUsesWith(NewPtr); OGV->eraseFromParent(); } - bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden; - if (Hidden) - GV->setVisibility(llvm::GlobalVariable::HiddenVisibility); } - llvm::Constant *vtable = llvm::ConstantExpr::getBitCast(GV, Ptr8Ty); - llvm::Constant *AddressPointC; - uint32_t LLVMPointerWidth = getContext().Target.getPointerWidth(0); - AddressPointC = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - AddressPoint*LLVMPointerWidth/8); - vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(vtable, &AddressPointC, - 1); - - assert(vtable->getType() == Ptr8Ty); - return vtable; + + return GV; } +namespace { class VTTBuilder { /// Inits - The list of values built for the VTT. std::vector<llvm::Constant *> &Inits; @@ -1125,12 +1220,13 @@ class VTTBuilder { llvm::LLVMContext &VMContext; /// BuildVtablePtr - Build up a referene to the given secondary vtable - llvm::Constant *BuildVtablePtr(llvm::Constant *vtbl, - const CXXRecordDecl *VtblClass, + llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable, + const CXXRecordDecl *VtableClass, const CXXRecordDecl *RD, uint64_t Offset) { - int64_t AddressPoint; - AddressPoint = (*AddressPoints[VtblClass])[std::make_pair(RD, Offset)]; + int64_t AddressPoint = + (*AddressPoints[VtableClass])[std::make_pair(RD, Offset)]; + // FIXME: We can never have 0 address point. Do this for now so gepping // retains the same structure. Later we'll just assert. if (AddressPoint == 0) @@ -1138,12 +1234,17 @@ class VTTBuilder { D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n", RD->getNameAsCString(), VtblClass->getNameAsCString(), Class->getNameAsCString(), (int)Offset, (int)AddressPoint)); - uint32_t LLVMPointerWidth = CGM.getContext().Target.getPointerWidth(0); - llvm::Constant *init; - init = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - AddressPoint*LLVMPointerWidth/8); - init = llvm::ConstantExpr::getInBoundsGetElementPtr(vtbl, &init, 1); - return init; + + llvm::Value *Idxs[] = { + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 0), + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), AddressPoint) + }; + + llvm::Constant *Init = + llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, Idxs, 2); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + return llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); } /// Secondary - Add the secondary vtable pointers to Inits. Offset is the @@ -1180,8 +1281,11 @@ class VTTBuilder { init = BuildVtablePtr(vtbl, VtblClass, RD, Offset); else { init = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseOffset); - subvtbl = dyn_cast<llvm::Constant>(init->getOperand(0)); + + subvtbl = init; subVtblClass = Base; + + init = BuildVtablePtr(init, Class, Base, BaseOffset); } Inits.push_back(init); } @@ -1195,25 +1299,26 @@ class VTTBuilder { if (RD->getNumVBases() == 0 && !MorallyVirtual) return; - llvm::Constant *init; - const CXXRecordDecl *VtblClass; + llvm::Constant *Vtable; + const CXXRecordDecl *VtableClass; // First comes the primary virtual table pointer... if (MorallyVirtual) { - init = BuildVtablePtr(ClassVtbl, Class, RD, Offset); - VtblClass = Class; + Vtable = ClassVtbl; + VtableClass = Class; } else { - init = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset); - VtblClass = RD; + Vtable = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset); + VtableClass = RD; } - llvm::Constant *vtbl = dyn_cast<llvm::Constant>(init->getOperand(0)); - Inits.push_back(init); + + llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset); + Inits.push_back(Init); // then the secondary VTTs.... SecondaryVTTs(RD, Offset, MorallyVirtual); // and last the secondary vtable pointers. - Secondary(RD, vtbl, VtblClass, Offset, MorallyVirtual); + Secondary(RD, Vtable, VtableClass, Offset, MorallyVirtual); } /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are @@ -1248,6 +1353,7 @@ class VTTBuilder { VirtualVTTs(Base); } } + public: VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c, CodeGenModule &cgm) @@ -1258,8 +1364,7 @@ public: // First comes the primary virtual table pointer for the complete class... ClassVtbl = CGM.getVtableInfo().getVtable(Class); - Inits.push_back(ClassVtbl); - ClassVtbl = dyn_cast<llvm::Constant>(ClassVtbl->getOperand(0)); + Inits.push_back(BuildVtablePtr(ClassVtbl, Class, Class, 0)); // then the secondary VTTs... SecondaryVTTs(Class); @@ -1271,98 +1376,116 @@ public: VirtualVTTs(Class); } }; +} -llvm::Constant *CodeGenModule::GenerateVTT(const CXXRecordDecl *RD) { +llvm::GlobalVariable * +CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD) { // Only classes that have virtual bases need a VTT. if (RD->getNumVBases() == 0) return 0; llvm::SmallString<256> OutName; - getMangleContext().mangleCXXVTT(RD, OutName); + CGM.getMangleContext().mangleCXXVTT(RD, OutName); llvm::StringRef Name = OutName.str(); - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::LinkOnceODRLinkage; - if (RD->isInAnonymousNamespace()) - linktype = llvm::GlobalValue::InternalLinkage; - std::vector<llvm::Constant *> inits; - llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); D1(printf("vtt %s\n", RD->getNameAsCString())); - VTTBuilder b(inits, RD, *this); - - llvm::Constant *C; - llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, inits.size()); - C = llvm::ConstantArray::get(type, inits); - llvm::GlobalVariable *vtt = new llvm::GlobalVariable(getModule(), type, true, - linktype, C, Name); - bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden; - if (Hidden) - vtt->setVisibility(llvm::GlobalVariable::HiddenVisibility); - return llvm::ConstantExpr::getBitCast(vtt, Ptr8Ty); -} + std::vector<llvm::Constant *> inits; + VTTBuilder b(inits, RD, CGM); -void CGVtableInfo::GenerateClassData(const CXXRecordDecl *RD) { - Vtables[RD] = CGM.GenerateVtable(RD, RD); - CGM.GenerateRtti(RD); - CGM.GenerateVTT(RD); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size()); + + llvm::Constant *Init = llvm::ConstantArray::get(Type, inits); + + llvm::GlobalVariable *VTT = + new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true, + Linkage, Init, Name); + CGM.setGlobalVisibility(VTT, RD); + + return VTT; } -llvm::Constant *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { - llvm::Constant *&vtbl = Vtables[RD]; - if (vtbl) - return vtbl; - vtbl = CGM.GenerateVtable(RD, RD); - - bool CreateDefinition = true; - - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) { - if (!KeyFunction->getBody()) { - // If there is a KeyFunction, and it isn't defined, just build a - // reference to the vtable. - CreateDefinition = false; - } +void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD) { + llvm::GlobalVariable *&Vtable = Vtables[RD]; + if (Vtable) { + assert(Vtable->getInitializer() && "Vtable doesn't have a definition!"); + return; } + + Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0); + GenerateVTT(Linkage, RD); +} - if (CreateDefinition) { - CGM.GenerateRtti(RD); - CGM.GenerateVTT(RD); - } - return vtbl; +llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { + llvm::GlobalVariable *Vtable = Vtables.lookup(RD); + + if (!Vtable) + Vtable = GenerateVtable(llvm::GlobalValue::ExternalLinkage, + /*GenerateDefinition=*/false, RD, RD, 0); + + return Vtable; } -llvm::Constant *CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, - uint64_t Offset) { - return CGM.GenerateVtable(LayoutClass, RD, Offset); +llvm::GlobalVariable * +CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass, + const CXXRecordDecl *RD, uint64_t Offset) { + return GenerateVtable(llvm::GlobalValue::InternalLinkage, + /*GenerateDefinition=*/true, + LayoutClass, RD, Offset); } void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); const CXXRecordDecl *RD = MD->getParent(); - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + // If the class doesn't have a vtable we don't need to emit one. + if (!RD->isDynamicClass()) + return; // Get the key function. - const CXXMethodDecl *KeyFunction = Layout.getKeyFunction(); + const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD); - if (!KeyFunction) { - // If there's no key function, we don't want to emit the vtable here. - return; + if (KeyFunction) { + // We don't have the right key function. + if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) + return; + + // If the key function is a destructor, we only want to emit the vtable + // once, so do it for the complete destructor. + if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Complete) + return; + } else { + // If there is no key function, we only want to emit the vtable if we are + // emitting a constructor. + if (!isa<CXXConstructorDecl>(MD) || GD.getCtorType() != Ctor_Complete) + return; } - // Check if we have the key function. - if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) - return; + llvm::GlobalVariable::LinkageTypes Linkage; + if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) + Linkage = llvm::GlobalVariable::InternalLinkage; + else if (KeyFunction && !MD->isInlined()) + Linkage = llvm::GlobalVariable::ExternalLinkage; + else + Linkage = llvm::GlobalVariable::WeakODRLinkage; - // If the key function is a destructor, we only want to emit the vtable once, - // so do it for the complete destructor. - if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Complete) - return; - // Emit the data. - GenerateClassData(RD); + GenerateClassData(Linkage, RD); + + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); i != e; ++i) { + if ((*i)->isVirtual() && ((*i)->hasInlineBody() || (*i)->isImplicit())) { + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(*i)) { + CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Complete)); + CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Deleting)); + } else { + CGM.BuildThunksForVirtual(GlobalDecl(*i)); + } + } + } } diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index 5c2b74c..eed5b64 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -15,12 +15,10 @@ #define CLANG_CODEGEN_CGVTABLE_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/GlobalVariable.h" #include "GlobalDecl.h" -namespace llvm { - class Constant; -} - namespace clang { class CXXRecordDecl; @@ -64,6 +62,11 @@ public: }; class CGVtableInfo { +public: + typedef std::vector<std::pair<GlobalDecl, ThunkAdjustment> > + AdjustmentVectorTy; + +private: CodeGenModule &CGM; /// MethodVtableIndices - Contains the index (relative to the vtable address @@ -79,12 +82,17 @@ class CGVtableInfo { typedef llvm::DenseMap<ClassPairTy, int64_t> VirtualBaseClassIndiciesTy; VirtualBaseClassIndiciesTy VirtualBaseClassIndicies; - llvm::DenseMap<const CXXRecordDecl *, llvm::Constant *> Vtables; + /// Vtables - All the vtables which have been defined. + llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> Vtables; /// NumVirtualFunctionPointers - Contains the number of virtual function /// pointers in the vtable for a given record decl. llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers; + typedef llvm::DenseMap<GlobalDecl, AdjustmentVectorTy> SavedAdjustmentsTy; + SavedAdjustmentsTy SavedAdjustments; + llvm::DenseSet<const CXXRecordDecl*> SavedAdjustmentRecords; + /// getNumVirtualFunctionPointers - Return the number of virtual function /// pointers in the vtable for a given record decl. uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); @@ -94,8 +102,19 @@ class CGVtableInfo { /// GenerateClassData - Generate all the class data requires to be generated /// upon definition of a KeyFunction. This includes the vtable, the /// rtti data structure and the VTT. - void GenerateClassData(const CXXRecordDecl *RD); - + /// + /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT. + void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD); + + llvm::GlobalVariable * + GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, + bool GenerateDefinition, const CXXRecordDecl *LayoutClass, + const CXXRecordDecl *RD, uint64_t Offset); + + llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD); + public: CGVtableInfo(CodeGenModule &CGM) : CGM(CGM) { } @@ -113,9 +132,17 @@ public: int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, const CXXRecordDecl *VBase); - llvm::Constant *getVtable(const CXXRecordDecl *RD); - llvm::Constant *getCtorVtable(const CXXRecordDecl *RD, - const CXXRecordDecl *Class, uint64_t Offset); + AdjustmentVectorTy *getAdjustments(GlobalDecl GD); + + /// getVtableAddressPoint - returns the address point of the vtable for the + /// given record decl. + /// FIXME: This should return a list of address points. + uint64_t getVtableAddressPoint(const CXXRecordDecl *RD); + + llvm::GlobalVariable *getVtable(const CXXRecordDecl *RD); + llvm::GlobalVariable *getCtorVtable(const CXXRecordDecl *RD, + const CXXRecordDecl *Class, + uint64_t Offset); void MaybeEmitVtable(GlobalDecl GD); diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 9281416..3c26484 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -8,6 +8,7 @@ add_clang_library(clangCodeGen CGCXX.cpp CGDebugInfo.cpp CGDecl.cpp + CGDeclCXX.cpp CGException.cpp CGExpr.cpp CGExprAgg.cpp @@ -19,7 +20,7 @@ add_clang_library(clangCodeGen CGObjCGNU.cpp CGObjCMac.cpp CGRecordLayoutBuilder.cpp - CGRtti.cpp + CGRTTI.cpp CGStmt.cpp CGTemporaries.cpp CGVtable.cpp diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 6e0a77c..28df9e4 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -19,6 +19,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/StmtCXX.h" #include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; @@ -30,9 +31,12 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) DebugInfo(0), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0), CXXThisDecl(0), CXXVTTDecl(0), - ConditionalBranchLevel(0) { + ConditionalBranchLevel(0), TerminateHandler(0), TrapBB(0), + UniqueAggrDestructorCount(0) { LLVMIntTy = ConvertType(getContext().IntTy); LLVMPointerWidth = Target.getPointerWidth(0); + Exceptions = getContext().getLangOptions().Exceptions; + CatchUndefined = getContext().getLangOptions().CatchUndefined; } ASTContext &CodeGenFunction::getContext() const { @@ -130,6 +134,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { } EmitFunctionEpilog(*CurFnInfo, ReturnValue); + EmitEndEHSpec(CurCodeDecl); // If someone did an indirect goto, emit the indirect goto block at the end of // the function. @@ -179,9 +184,6 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, AllocaInsertPt->setName("allocapt"); ReturnBlock = createBasicBlock("return"); - ReturnValue = 0; - if (!RetTy->isVoidType()) - ReturnValue = CreateTempAlloca(ConvertType(RetTy), "retval"); Builder.SetInsertPoint(EntryBB); @@ -195,15 +197,26 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, DI->EmitFunctionStart(CGM.getMangledName(GD), FnType, CurFn, Builder); } else { // Just use LLVM function name. - - // FIXME: Remove unnecessary conversion to std::string when API settles. - DI->EmitFunctionStart(std::string(Fn->getName()).c_str(), - FnType, CurFn, Builder); + DI->EmitFunctionStart(Fn->getName(), FnType, CurFn, Builder); } } // FIXME: Leaked. CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args); + + if (RetTy->isVoidType()) { + // Void type; nothing to return. + ReturnValue = 0; + } 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++. + ReturnValue = CurFn->arg_begin(); + } else { + ReturnValue = CreateTempAlloca(ConvertType(RetTy), "retval"); + } + + EmitStartEHSpec(CurCodeDecl); EmitFunctionProlog(*CurFnInfo, CurFn, Args); // If any of the arguments have a variably modified type, make sure to @@ -245,6 +258,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, FunctionArgList Args; + CurGD = GD; + OuterTryBlock = 0; if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { if (MD->isInstance()) { // Create the implicit 'this' decl. @@ -276,7 +291,6 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, FProto->getArgType(i))); } - // FIXME: Support CXXTryStmt here, too. if (const CompoundStmt *S = FD->getCompoundBody()) { StartFunction(GD, FD->getResultType(), Fn, Args, S->getLBracLoc()); @@ -341,6 +355,13 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, } 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()); + } } // Destroy the 'this' declaration. @@ -606,8 +627,11 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) { } void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock, - llvm::BasicBlock *CleanupExitBlock) { - CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock)); + llvm::BasicBlock *CleanupExitBlock, + llvm::BasicBlock *PreviousInvokeDest, + bool EHOnly) { + CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock, + PreviousInvokeDest, EHOnly)); } void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) { @@ -629,6 +653,10 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { std::vector<llvm::BranchInst *> BranchFixups; std::swap(BranchFixups, CE.BranchFixups); + bool EHOnly = CE.EHOnly; + + setInvokeDest(CE.PreviousInvokeDest); + CleanupEntries.pop_back(); // Check if any branch fixups pointed to the scope we just popped. If so, @@ -663,8 +691,9 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { Builder.SetInsertPoint(SwitchBlock); - llvm::Value *DestCodePtr = CreateTempAlloca(llvm::Type::getInt32Ty(VMContext), - "cleanup.dst"); + llvm::Value *DestCodePtr + = CreateTempAlloca(llvm::Type::getInt32Ty(VMContext), + "cleanup.dst"); llvm::Value *DestCode = Builder.CreateLoad(DestCodePtr, "tmp"); // Create a switch instruction to determine where to jump next. @@ -710,15 +739,16 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { new llvm::StoreInst(ID, DestCodePtr, BI); } else { // We need to jump through another cleanup block. Create a pad block - // with a branch instruction that jumps to the final destination and - // add it as a branch fixup to the current cleanup scope. + // with a branch instruction that jumps to the final destination and add + // it as a branch fixup to the current cleanup scope. // Create the pad block. llvm::BasicBlock *CleanupPad = createBasicBlock("cleanup.pad", CurFn); // Create a unique case ID. - llvm::ConstantInt *ID = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - SI->getNumSuccessors()); + llvm::ConstantInt *ID + = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + SI->getNumSuccessors()); // Store the jump destination before the branch instruction. new llvm::StoreInst(ID, DestCodePtr, BI); @@ -744,12 +774,19 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { BlockScopes.erase(Blocks[i]); } - return CleanupBlockInfo(CleanupEntryBlock, SwitchBlock, EndBlock); + return CleanupBlockInfo(CleanupEntryBlock, SwitchBlock, EndBlock, EHOnly); } void CodeGenFunction::EmitCleanupBlock() { CleanupBlockInfo Info = PopCleanupBlock(); + if (Info.EHOnly) { + // FIXME: Add this to the exceptional edge + if (Info.CleanupBlock->getNumUses() == 0) + delete Info.CleanupBlock; + return; + } + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); if (CurBB && !CurBB->getTerminator() && Info.CleanupBlock->getNumUses() == 0) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 7f32045..12e636c 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -88,11 +88,17 @@ public: QualType FnRetTy; llvm::Function *CurFn; + /// 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; /// ReturnValue - The temporary alloca to hold the return value. This is null /// iff the function has no return value. - llvm::Instruction *ReturnValue; + llvm::Value *ReturnValue; /// AllocaInsertPoint - This is an instruction in the entry block before which /// we prefer to insert allocas. @@ -101,6 +107,8 @@ public: const llvm::Type *LLVMIntTy; uint32_t LLVMPointerWidth; + bool Exceptions; + bool CatchUndefined; public: /// ObjCEHValueStack - Stack of Objective-C exception values, used for /// rethrows. @@ -109,7 +117,12 @@ public: /// PushCleanupBlock - Push a new cleanup entry on the stack and set the /// passed in block as the cleanup block. void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock, - llvm::BasicBlock *CleanupExitBlock = 0); + llvm::BasicBlock *CleanupExitBlock, + llvm::BasicBlock *PreviousInvokeDest, + bool EHOnly = false); + void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock) { + PushCleanupBlock(CleanupEntryBlock, 0, getInvokeDest(), false); + } /// CleanupBlockInfo - A struct representing a popped cleanup block. struct CleanupBlockInfo { @@ -123,14 +136,43 @@ public: /// EndBlock - the default destination for the switch instruction. llvm::BasicBlock *EndBlock; + /// EHOnly - True iff this cleanup should only be performed on the + /// exceptional edge. + bool EHOnly; + CleanupBlockInfo(llvm::BasicBlock *cb, llvm::BasicBlock *sb, - llvm::BasicBlock *eb) - : CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb) {} + llvm::BasicBlock *eb, bool ehonly = false) + : CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb), EHOnly(ehonly) {} + }; + + /// EHCleanupBlock - RAII object that will create a cleanup block for the + /// exceptional edge and set the insert point to that block. When destroyed, + /// it creates the cleanup edge and sets the insert point to the previous + /// block. + class EHCleanupBlock { + CodeGenFunction& CGF; + llvm::BasicBlock *Cont; + llvm::BasicBlock *CleanupHandler; + llvm::BasicBlock *CleanupEntryBB; + llvm::BasicBlock *PreviousInvokeDest; + public: + EHCleanupBlock(CodeGenFunction &cgf) + : CGF(cgf), Cont(CGF.createBasicBlock("cont")), + CleanupHandler(CGF.createBasicBlock("ehcleanup")), + CleanupEntryBB(CGF.createBasicBlock("ehcleanup.rest")), + PreviousInvokeDest(CGF.getInvokeDest()) { + CGF.EmitBranch(Cont); + llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); + CGF.Builder.SetInsertPoint(CleanupEntryBB); + CGF.setInvokeDest(TerminateHandler); + } + ~EHCleanupBlock(); }; /// PopCleanupBlock - Will pop the cleanup entry on the stack, process all /// branch fixups and return a block info struct with the switch block and end - /// block. + /// block. This will also reset the invoke handler to the previous value + /// from when the cleanup block was created. CleanupBlockInfo PopCleanupBlock(); /// DelayedCleanupBlock - RAII object that will create a cleanup block and set @@ -141,11 +183,15 @@ public: llvm::BasicBlock *CurBB; llvm::BasicBlock *CleanupEntryBB; llvm::BasicBlock *CleanupExitBB; + llvm::BasicBlock *CurInvokeDest; + bool EHOnly; public: - DelayedCleanupBlock(CodeGenFunction &cgf) + DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false) : CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()), - CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0) { + CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0), + CurInvokeDest(CGF.getInvokeDest()), + EHOnly(ehonly) { CGF.Builder.SetInsertPoint(CleanupEntryBB); } @@ -156,7 +202,8 @@ public: } ~DelayedCleanupBlock() { - CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB); + CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB, CurInvokeDest, + EHOnly); // FIXME: This is silly, move this into the builder. if (CurBB) CGF.Builder.SetInsertPoint(CurBB); @@ -303,10 +350,21 @@ private: /// inserted into the current function yet. std::vector<llvm::BranchInst *> BranchFixups; + /// PreviousInvokeDest - The invoke handler from the start of the cleanup + /// region. + llvm::BasicBlock *PreviousInvokeDest; + + /// EHOnly - Perform this only on the exceptional edge, not the main edge. + bool EHOnly; + explicit CleanupEntry(llvm::BasicBlock *CleanupEntryBlock, - llvm::BasicBlock *CleanupExitBlock) - : CleanupEntryBlock(CleanupEntryBlock), - CleanupExitBlock(CleanupExitBlock) {} + llvm::BasicBlock *CleanupExitBlock, + llvm::BasicBlock *PreviousInvokeDest, + bool ehonly) + : CleanupEntryBlock(CleanupEntryBlock), + CleanupExitBlock(CleanupExitBlock), + PreviousInvokeDest(PreviousInvokeDest), + EHOnly(ehonly) {} }; /// CleanupEntries - Stack of cleanup entries. @@ -365,7 +423,11 @@ private: /// getByrefValueFieldNumber - Given a declaration, returns the LLVM field /// number that holds the value. unsigned getByRefValueLLVMField(const ValueDecl *VD) const; - + + llvm::BasicBlock *TerminateHandler; + llvm::BasicBlock *TrapBB; + + int UniqueAggrDestructorCount; public: CodeGenFunction(CodeGenModule &cgm); @@ -441,16 +503,18 @@ public: const ThunkAdjustment &Adjustment); /// GenerateThunk - Generate a thunk for the given method - llvm::Constant *GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, + llvm::Constant *GenerateThunk(llvm::Function *Fn, GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment); llvm::Constant * - GenerateCovariantThunk(llvm::Function *Fn, const CXXMethodDecl *MD, + GenerateCovariantThunk(llvm::Function *Fn, GlobalDecl GD, bool Extern, const CovariantThunkAdjustment &Adjustment); void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type); + void InitializeVtablePtrs(const CXXRecordDecl *ClassDecl); + void SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, CXXCtorType Type, llvm::Function *Fn, @@ -487,6 +551,15 @@ public: /// given temporary. void EmitFunctionEpilog(const CGFunctionInfo &FI, llvm::Value *ReturnValue); + /// EmitStartEHSpec - Emit the start of the exception spec. + void EmitStartEHSpec(const Decl *D); + + /// EmitEndEHSpec - Emit the end of the exception spec. + void EmitEndEHSpec(const Decl *D); + + /// getTerminateHandler - Return a handler that just calls terminate. + llvm::BasicBlock *getTerminateHandler(); + const llvm::Type *ConvertTypeForMem(QualType T); const llvm::Type *ConvertType(QualType T); @@ -903,6 +976,7 @@ public: LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E); LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E); LValue EmitMemberExpr(const MemberExpr *E); + LValue EmitObjCIsaExpr(const ObjCIsaExpr *E); LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E); LValue EmitConditionalOperatorLValue(const ConditionalOperator *E); LValue EmitCastLValue(const CastExpr *E); @@ -1059,9 +1133,18 @@ public: /// CreateStaticBlockVarDecl - Create a zero-initialized LLVM global for a /// static block var decl. - llvm::GlobalVariable * CreateStaticBlockVarDecl(const VarDecl &D, - const char *Separator, + llvm::GlobalVariable *CreateStaticBlockVarDecl(const VarDecl &D, + const char *Separator, llvm::GlobalValue::LinkageTypes Linkage); + + /// AddInitializerToGlobalBlockVarDecl - Add the initializer for 'D' to the + /// global variable that has already been created for it. If the initializer + /// has a different type than GV does, this may free GV and return a different + /// one. Otherwise it just returns GV. + llvm::GlobalVariable * + AddInitializerToGlobalBlockVarDecl(const VarDecl &D, + llvm::GlobalVariable *GV); + /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++ runtime /// initialized static block var decl. @@ -1112,6 +1195,10 @@ public: /// try to simplify the codegen of the conditional based on the branch. void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock, llvm::BasicBlock *FalseBlock); + + /// getTrapBB - Create a basic block that will call the trap intrinsic. We'll + /// generate a branch around the created basic block as necessary. + llvm::BasicBlock* getTrapBB(); private: void EmitReturnOfRValue(RValue RV, QualType Ty); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 4b3b122..761f343 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -56,7 +56,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, Runtime = CreateMacObjCRuntime(*this); // If debug info generation is enabled, create the CGDebugInfo object. - DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(this) : 0; + DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(*this) : 0; } CodeGenModule::~CodeGenModule() { @@ -256,9 +256,18 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, // The kind of external linkage this function will have, if it is not // inline or static. CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal; - if (Context.getLangOptions().CPlusPlus && - FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) - External = CodeGenModule::GVA_TemplateInstantiation; + if (Context.getLangOptions().CPlusPlus) { + TemplateSpecializationKind TSK = FD->getTemplateSpecializationKind(); + + if (TSK == TSK_ExplicitInstantiationDefinition) { + // If a function has been explicitly instantiated, then it should + // always have strong external linkage. + return CodeGenModule::GVA_StrongExternal; + } + + if (TSK == TSK_ImplicitInstantiation) + External = CodeGenModule::GVA_TemplateInstantiation; + } if (!FD->isInlined()) return External; @@ -522,6 +531,16 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { FD->hasAttr<DestructorAttr>()) return false; + // The key function for a class must never be deferred. + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Global)) { + const CXXRecordDecl *RD = MD->getParent(); + if (MD->isOutOfLine() && RD->isDynamicClass()) { + const CXXMethodDecl *KeyFunction = getContext().getKeyFunction(RD); + if (KeyFunction == MD->getCanonicalDecl()) + return false; + } + } + GVALinkage Linkage = GetLinkageForFunction(getContext(), FD, Features); // static, static inline, always_inline, and extern inline functions can @@ -576,11 +595,17 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { const VarDecl *VD = cast<VarDecl>(Global); assert(VD->isFileVarDecl() && "Cannot emit local var decl as global."); - // In C++, if this is marked "extern", defer code generation. - if (getLangOptions().CPlusPlus && !VD->getInit() && - (VD->getStorageClass() == VarDecl::Extern || - VD->isExternC())) - return; + if (getLangOptions().CPlusPlus && !VD->getInit()) { + // In C++, if this is marked "extern", defer code generation. + if (VD->getStorageClass() == VarDecl::Extern || VD->isExternC()) + return; + + // If this is a declaration of an explicit specialization of a static + // data member in a class template, don't emit it. + if (VD->isStaticDataMember() && + VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return; + } // In C, if this isn't a definition, defer code generation. if (!getLangOptions().CPlusPlus && !VD->getInit()) @@ -615,8 +640,19 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { Context.getSourceManager(), "Generating code for declaration"); - if (isa<CXXMethodDecl>(D)) + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { getVtableInfo().MaybeEmitVtable(GD); + if (MD->isVirtual() && MD->isOutOfLine() && + (!isa<CXXDestructorDecl>(D) || GD.getDtorType() != Dtor_Base)) { + if (isa<CXXDestructorDecl>(D)) { + GlobalDecl CanonGD(cast<CXXDestructorDecl>(D->getCanonicalDecl()), + GD.getDtorType()); + BuildThunksForVirtual(CanonGD); + } else { + BuildThunksForVirtual(MD->getCanonicalDecl()); + } + } + } if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D)) EmitCXXConstructor(CD, GD.getCtorType()); @@ -724,6 +760,17 @@ CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy, return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl()); } +static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) { + if (!D->getType().isConstant(Context)) + return false; + if (Context.getLangOptions().CPlusPlus && + Context.getBaseElementType(D->getType())->getAs<RecordType>()) { + // FIXME: We should do something fancier here! + return false; + } + return true; +} + /// GetOrCreateLLVMGlobal - If the specified mangled name is not in the module, /// create and return an llvm GlobalVariable with the specified type. If there /// is something in the module with the specified name, return it potentially @@ -767,7 +814,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName, if (D) { // FIXME: This code is overly simple and should be merged with other global // handling. - GV->setConstant(D->getType().isConstant(Context)); + GV->setConstant(DeclIsConstantGlobal(Context, D)); // FIXME: Merge with other attribute handling code. if (D->getStorageClass() == VarDecl::PrivateExtern) @@ -844,7 +891,7 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { return CodeGenModule::GVA_StrongExternal; case TSK_ExplicitInstantiationDeclaration: - llvm::llvm_unreachable("Variable should not be instantiated"); + llvm_unreachable("Variable should not be instantiated"); // Fall through to treat this like any other instantiation. case TSK_ImplicitInstantiation: @@ -942,11 +989,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { // If it is safe to mark the global 'constant', do so now. GV->setConstant(false); - if (D->getType().isConstant(Context)) { - // FIXME: In C++, if the variable has a non-trivial ctor/dtor or any mutable - // members, it cannot be declared "LLVM const". + if (DeclIsConstantGlobal(Context, D)) GV->setConstant(true); - } GV->setAlignment(getContext().getDeclAlignInBytes(D)); @@ -1226,13 +1270,8 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, if (Context.BuiltinInfo.isLibFunction(BuiltinID)) Name += 10; - // Get the type for the builtin. - ASTContext::GetBuiltinTypeError Error; - QualType Type = Context.GetBuiltinType(BuiltinID, Error); - assert(Error == ASTContext::GE_None && "Can't get builtin type"); - const llvm::FunctionType *Ty = - cast<llvm::FunctionType>(getTypes().ConvertType(Type)); + cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType())); // Unique the name through the identifier table. Name = getContext().Idents.get(Name).getNameStart(); @@ -1658,14 +1697,13 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::FileScopeAsm: { FileScopeAsmDecl *AD = cast<FileScopeAsmDecl>(D); - std::string AsmString(AD->getAsmString()->getStrData(), - AD->getAsmString()->getByteLength()); + llvm::StringRef AsmString = AD->getAsmString()->getString(); const std::string &S = getModule().getModuleInlineAsm(); if (S.empty()) getModule().setModuleInlineAsm(AsmString); else - getModule().setModuleInlineAsm(S + '\n' + AsmString); + getModule().setModuleInlineAsm(S + '\n' + AsmString.str()); break; } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 78bc4ed..cc7ec9c 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -212,34 +212,38 @@ public: llvm::Constant *GetAddrOfFunction(GlobalDecl GD, const llvm::Type *Ty = 0); - /// GenerateVtable - Generate the vtable for the given type. LayoutClass is - /// the class to use for the virtual base layout information. For - /// non-construction vtables, this is always the same as RD. Offset is the - /// offset in bits for the RD object in the LayoutClass, if we're generating a - /// construction vtable, otherwise 0. - llvm::Constant *GenerateVtable(const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, - uint64_t Offset=0); - - /// GenerateVTT - Generate the VTT for the given type. - llvm::Constant *GenerateVTT(const CXXRecordDecl *RD); - - /// GenerateRtti - Generate the rtti information for the given type. - llvm::Constant *GenerateRtti(const CXXRecordDecl *RD); - /// GenerateRttiRef - Generate a reference to the rtti information for the + /// GetAddrOfRTTI - Get the address of the RTTI structure for the given type. + llvm::Constant *GetAddrOfRTTI(QualType Ty); + + /// GetAddrOfRTTI - Get the address of the RTTI structure for the given record + /// decl. + llvm::Constant *GetAddrOfRTTI(const CXXRecordDecl *RD); + + /// GenerateRTTI - Generate the rtti information for the given type. + llvm::Constant *GenerateRTTI(const CXXRecordDecl *RD); + + /// GenerateRTTIRef - Generate a reference to the rtti information for the /// given type. - llvm::Constant *GenerateRttiRef(const CXXRecordDecl *RD); - /// GenerateRttiNonClass - Generate the rtti information for the given + llvm::Constant *GenerateRTTIRef(const CXXRecordDecl *RD); + + /// GenerateRTTI - Generate the rtti information for the given /// non-class type. - llvm::Constant *GenerateRtti(QualType Ty); + llvm::Constant *GenerateRTTI(QualType Ty); + + llvm::Constant *GetAddrOfThunk(GlobalDecl GD, + const ThunkAdjustment &ThisAdjustment); + llvm::Constant *GetAddrOfCovariantThunk(GlobalDecl GD, + const CovariantThunkAdjustment &ThisAdjustment); + void BuildThunksForVirtual(GlobalDecl GD); + void BuildThunksForVirtualRecursive(GlobalDecl GD, GlobalDecl BaseOGD); /// BuildThunk - Build a thunk for the given method. - llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, + llvm::Constant *BuildThunk(GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment); /// BuildCoVariantThunk - Build a thunk for the given method llvm::Constant * - BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern, + BuildCovariantThunk(const GlobalDecl &GD, bool Extern, const CovariantThunkAdjustment &Adjustment); typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t; @@ -252,6 +256,11 @@ public: llvm::Constant *GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl); + /// ComputeThunkAdjustment - Returns the two parts required to compute the + /// offset for an object. + ThunkAdjustment ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl); + /// GetStringForStringLiteral - Return the appropriate bytes for a string /// literal, properly padded to match the literal type. If only the address of /// a constant is needed consider using GetAddrOfConstantStringLiteral. diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index c89879f..cd3575c 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -379,13 +379,13 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { // If we ever want to support other ABIs this needs to be abstracted. QualType ETy = cast<MemberPointerType>(Ty).getPointeeType(); + const llvm::Type *PtrDiffTy = + ConvertTypeRecursive(Context.getPointerDiffType()); if (ETy->isFunctionType()) { - return llvm::StructType::get(TheModule.getContext(), - ConvertType(Context.getPointerDiffType()), - ConvertType(Context.getPointerDiffType()), + return llvm::StructType::get(TheModule.getContext(), PtrDiffTy, PtrDiffTy, NULL); } else - return ConvertType(Context.getPointerDiffType()); + return PtrDiffTy; } case Type::TemplateSpecialization: diff --git a/lib/CodeGen/GlobalDecl.h b/lib/CodeGen/GlobalDecl.h index b812020..b054312 100644 --- a/lib/CodeGen/GlobalDecl.h +++ b/lib/CodeGen/GlobalDecl.h @@ -96,15 +96,14 @@ namespace llvm { return LHS == RHS; } - static bool isPod() { - // GlobalDecl isn't *technically* a POD type. However, we can get - // away with calling it a POD type since its copy constructor, - // copy assignment operator, and destructor are all trivial. - return true; - } - }; -} + // GlobalDecl isn't *technically* a POD type. However, its copy constructor, + // copy assignment operator, and destructor are all trivial. + template <> + struct isPodLike<clang::CodeGen::GlobalDecl> { + static const bool value = true; + }; +} // end namespace llvm #endif diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index d6f7808..90cc894 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -89,8 +89,6 @@ private: void addSubstitution(QualType T); void addSubstitution(uintptr_t Ptr); - bool mangleFunctionDecl(const FunctionDecl *FD); - void mangleName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -99,7 +97,7 @@ private: void mangleUnscopedTemplateName(const TemplateDecl *ND); void mangleSourceName(const IdentifierInfo *II); void mangleLocalName(const NamedDecl *ND); - void mangleNestedName(const NamedDecl *ND); + void mangleNestedName(const NamedDecl *ND, const DeclContext *DC); void mangleNestedName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -108,6 +106,8 @@ private: void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); void mangleQualifiers(Qualifiers Quals); + void mangleObjCMethodName(const ObjCMethodDecl *MD); + // Declare manglers for every type class. #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) @@ -117,6 +117,8 @@ private: void mangleType(const TagType*); void mangleBareFunctionType(const FunctionType *T, bool MangleReturnType); + + void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value); void mangleExpression(const Expr *E); void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); @@ -169,11 +171,19 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { isInExternCSystemHeader(D->getLocation())) return false; - // C functions, "main", and variables at global scope are not - // mangled. - if ((FD && FD->isMain()) || - (!FD && D->getDeclContext()->isTranslationUnit()) || - isInCLinkageSpecification(D)) + // Variables at global scope are not mangled. + if (!FD) { + const DeclContext *DC = D->getDeclContext(); + // Check for extern variable declared locally. + if (isa<FunctionDecl>(DC) && D->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = DC->getParent(); + if (DC->isTranslationUnit()) + return false; + } + + // C functions and "main" are not mangled. + if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) return false; return true; @@ -241,14 +251,32 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { mangleBareFunctionType(FT, MangleReturnType); } -static bool isStdNamespace(const NamespaceDecl *NS) { +/// isStd - Return whether a given namespace is the 'std' namespace. +static bool isStd(const NamespaceDecl *NS) { const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier(); return II && II->isStr("std"); } +static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { + while (isa<LinkageSpecDecl>(DC)) { + assert(cast<LinkageSpecDecl>(DC)->getLanguage() == + LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!"); + DC = DC->getParent(); + } + + return DC; +} + +// isStdNamespace - Return whether a given decl context is a toplevel 'std' +// namespace. static bool isStdNamespace(const DeclContext *DC) { - return DC->isNamespace() && DC->getParent()->isTranslationUnit() && - isStdNamespace(cast<NamespaceDecl>(DC)); + if (!DC->isNamespace()) + return false; + + if (!IgnoreLinkageSpecDecls(DC->getParent())->isTranslationUnit()) + return false; + + return isStd(cast<NamespaceDecl>(DC)); } static const TemplateDecl * @@ -278,6 +306,13 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { // ::= <local-name> // const DeclContext *DC = ND->getDeclContext(); + + // If this is an extern variable declared locally, the relevant DeclContext + // is that of the containing namespace, or the translation unit. + if (isa<FunctionDecl>(DC) && ND->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = DC->getParent(); + while (isa<LinkageSpecDecl>(DC)) DC = DC->getParent(); @@ -294,22 +329,17 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { return; } - if (isa<FunctionDecl>(DC)) { + if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) { mangleLocalName(ND); return; } - mangleNestedName(ND); + mangleNestedName(ND, DC); } void CXXNameMangler::mangleName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { - const DeclContext *DC = TD->getDeclContext(); - while (isa<LinkageSpecDecl>(DC)) { - assert(cast<LinkageSpecDecl>(DC)->getLanguage() == - LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!"); - DC = DC->getParent(); - } + const DeclContext *DC = IgnoreLinkageSpecDecls(TD->getDeclContext()); if (DC->isTranslationUnit() || isStdNamespace(DC)) { mangleUnscopedTemplateName(TD); @@ -456,8 +486,8 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { break; case DeclarationName::CXXLiteralOperatorName: - // Guessing based on existing ABI. - Out << "ul"; + // FIXME: This mangling is not yet official. + Out << "li"; mangleSourceName(Name.getCXXLiteralIdentifier()); break; @@ -474,7 +504,8 @@ void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) { Out << II->getLength() << II->getName(); } -void CXXNameMangler::mangleNestedName(const NamedDecl *ND) { +void CXXNameMangler::mangleNestedName(const NamedDecl *ND, + const DeclContext *DC) { // <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E // ::= N [<CV-qualifiers>] <template-prefix> <template-args> E @@ -488,7 +519,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND) { mangleTemplatePrefix(TD); mangleTemplateArgumentList(*TemplateArgs); } else { - manglePrefix(ND->getDeclContext()); + manglePrefix(DC); mangleUnqualifiedName(ND); } @@ -512,9 +543,14 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { // := Z <function encoding> E s [<discriminator>] // <discriminator> := _ <non-negative number> Out << 'Z'; - mangleFunctionEncoding(cast<FunctionDecl>(ND->getDeclContext())); + + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND->getDeclContext())) + mangleObjCMethodName(MD); + else + mangleFunctionEncoding(cast<FunctionDecl>(ND->getDeclContext())); + Out << 'E'; - mangleSourceName(ND->getIdentifier()); + mangleUnqualifiedName(ND); } void CXXNameMangler::manglePrefix(const DeclContext *DC) { @@ -523,7 +559,6 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) { // ::= <template-param> // ::= # empty // ::= <substitution> - // FIXME: We only handle mangling of namespaces and classes at the moment. while (isa<LinkageSpecDecl>(DC)) DC = DC->getParent(); @@ -654,10 +689,13 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { case OO_Call: Out << "cl"; break; // ::= ix # [] case OO_Subscript: Out << "ix"; break; - // UNSUPPORTED: ::= qu # ? + + // ::= qu # ? + // The conditional operator can't be overloaded, but we still handle it when + // mangling expressions. + case OO_Conditional: Out << "qu"; break; case OO_None: - case OO_Conditional: case NUM_OVERLOADED_OPERATORS: assert(false && "Not an overloaded operator"); break; @@ -676,6 +714,21 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { // FIXME: For now, just drop all extension qualifiers on the floor. } +void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { + llvm::SmallString<64> Name; + llvm::raw_svector_ostream OS(Name); + + const ObjCContainerDecl *CD = + dyn_cast<ObjCContainerDecl>(MD->getDeclContext()); + assert (CD && "Missing container decl in GetNameForMethod"); + OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName(); + if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD)) + OS << '(' << CID->getNameAsString() << ')'; + OS << ' ' << MD->getSelector().getAsString() << ']'; + + Out << OS.str().size() << OS.str(); +} + void CXXNameMangler::mangleType(QualType T) { // Only operate on the canonical type! T = Context.getASTContext().getCanonicalType(T); @@ -694,7 +747,7 @@ void CXXNameMangler::mangleType(QualType T) { #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) \ case Type::CLASS: \ - llvm::llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ + llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ return; #define TYPE(CLASS, PARENT) \ case Type::CLASS: \ @@ -788,7 +841,7 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) { Out << 'E'; } void CXXNameMangler::mangleType(const FunctionNoProtoType *T) { - llvm::llvm_unreachable("Can't mangle K&R function prototypes"); + llvm_unreachable("Can't mangle K&R function prototypes"); } void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, bool MangleReturnType) { @@ -816,6 +869,12 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, // <type> ::= <class-enum-type> // <class-enum-type> ::= <name> +void CXXNameMangler::mangleType(const UnresolvedUsingType *T) { + mangleName(T->getDecl()); +} + +// <type> ::= <class-enum-type> +// <class-enum-type> ::= <name> void CXXNameMangler::mangleType(const EnumType *T) { mangleType(static_cast<const TagType*>(T)); } @@ -823,10 +882,7 @@ void CXXNameMangler::mangleType(const RecordType *T) { mangleType(static_cast<const TagType*>(T)); } void CXXNameMangler::mangleType(const TagType *T) { - if (!T->getDecl()->getIdentifier()) - mangleName(T->getDecl()->getTypedefForAnonDecl()); - else - mangleName(T->getDecl()); + mangleName(T->getDecl()); } // <type> ::= <array-type> @@ -960,6 +1016,24 @@ void CXXNameMangler::mangleType(const TypenameType *T) { Out << 'E'; } +void CXXNameMangler::mangleIntegerLiteral(QualType T, + const llvm::APSInt &Value) { + // <expr-primary> ::= L <type> <value number> E # integer literal + Out << 'L'; + + mangleType(T); + if (T->isBooleanType()) { + // Boolean values are encoded as 0/1. + Out << (Value.getBoolValue() ? '1' : '0'); + } else { + if (Value.isNegative()) + Out << 'n'; + Value.abs().print(Out, false); + } + Out << 'E'; + +} + void CXXNameMangler::mangleExpression(const Expr *E) { // <expression> ::= <unary operator-name> <expression> // ::= <binary operator-name> <expression> <expression> @@ -978,6 +1052,32 @@ void CXXNameMangler::mangleExpression(const Expr *E) { switch (E->getStmtClass()) { default: assert(false && "Unhandled expression kind!"); + case Expr::UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(E); + mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()), + /*Arity=*/1); + mangleExpression(UO->getSubExpr()); + break; + } + + case Expr::BinaryOperatorClass: { + const BinaryOperator *BO = cast<BinaryOperator>(E); + mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()), + /*Arity=*/2); + mangleExpression(BO->getLHS()); + mangleExpression(BO->getRHS()); + break; + } + + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *CO = cast<ConditionalOperator>(E); + mangleOperatorName(OO_Conditional, /*Arity=*/3); + mangleExpression(CO->getCond()); + mangleExpression(CO->getLHS()); + mangleExpression(CO->getRHS()); + break; + } + case Expr::ParenExprClass: mangleExpression(cast<ParenExpr>(E)->getSubExpr()); break; @@ -1014,6 +1114,11 @@ void CXXNameMangler::mangleExpression(const Expr *E) { break; } + case Expr::IntegerLiteralClass: + mangleIntegerLiteral(E->getType(), + llvm::APSInt(cast<IntegerLiteral>(E)->getValue())); + break; + } } @@ -1090,23 +1195,9 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) { mangleExpression(A.getAsExpr()); Out << 'E'; break; - case TemplateArgument::Integral: { - // <expr-primary> ::= L <type> <value number> E # integer literal - - const llvm::APSInt *Integral = A.getAsIntegral(); - Out << 'L'; - mangleType(A.getIntegralType()); - if (A.getIntegralType()->isBooleanType()) { - // Boolean values are encoded as 0/1. - Out << (Integral->getBoolValue() ? '1' : '0'); - } else { - if (Integral->isNegative()) - Out << 'n'; - Integral->abs().print(Out, false); - } - Out << 'E'; + case TemplateArgument::Integral: + mangleIntegerLiteral(A.getIntegralType(), *A.getAsIntegral()); break; - } case TemplateArgument::Declaration: { // <expr-primary> ::= L <mangled-name> E # external name @@ -1228,12 +1319,29 @@ static bool isCharSpecialization(QualType T, const char *Name) { return SD->getIdentifier()->getName() == Name; } +template <std::size_t StrLen> +bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl *SD, + const char (&Str)[StrLen]) { + if (!SD->getIdentifier()->isStr(Str)) + return false; + + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); + if (TemplateArgs.size() != 2) + return false; + + if (!isCharType(TemplateArgs[0].getAsType())) + return false; + + if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) + return false; + + return true; +} + bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { // <substitution> ::= St # ::std:: - // FIXME: type_info == comes out as __ZNK3std9type_infoeqERKS0_ instead of - // __ZNKSt9type_infoeqERKS_ if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { - if (isStdNamespace(NS)) { + if (isStd(NS)) { Out << "St"; return true; } @@ -1280,23 +1388,26 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { return true; } - // <substitution> ::= So # ::std::basic_ostream<char, + // <substitution> ::= Si # ::std::basic_istream<char, // ::std::char_traits<char> > - if (SD->getIdentifier()->isStr("basic_ostream")) { - const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); - - if (TemplateArgs.size() != 2) - return false; - - if (!isCharType(TemplateArgs[0].getAsType())) - return false; - - if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) - return false; + if (isStreamCharSpecialization(SD, "basic_istream")) { + Out << "Si"; + return true; + } + // <substitution> ::= So # ::std::basic_ostream<char, + // ::std::char_traits<char> > + if (isStreamCharSpecialization(SD, "basic_ostream")) { Out << "So"; return true; } + + // <substitution> ::= Sd # ::std::basic_iostream<char, + // ::std::char_traits<char> > + if (isStreamCharSpecialization(SD, "basic_iostream")) { + Out << "Sd"; + return true; + } } return false; } @@ -1362,7 +1473,6 @@ void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, void MangleContext::mangleThunk(const FunctionDecl *FD, const ThunkAdjustment &ThisAdjustment, llvm::SmallVectorImpl<char> &Res) { - // FIXME: Hum, we might have to thunk these, fix. assert(!isa<CXXDestructorDecl>(FD) && "Use mangleCXXDtor for destructor decls!"); @@ -1374,15 +1484,26 @@ void MangleContext::mangleThunk(const FunctionDecl *FD, Mangler.mangleFunctionEncoding(FD); } +void MangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *D, + CXXDtorType Type, + const ThunkAdjustment &ThisAdjustment, + llvm::SmallVectorImpl<char> &Res) { + // <special-name> ::= T <call-offset> <base encoding> + // # base is the nominal target function of thunk + CXXNameMangler Mangler(*this, Res, D, Type); + Mangler.getStream() << "_ZT"; + Mangler.mangleCallOffset(ThisAdjustment); + Mangler.mangleFunctionEncoding(D); +} + /// \brief Mangles the a covariant thunk for the declaration D and emits that /// name to the given output stream. void MangleContext::mangleCovariantThunk(const FunctionDecl *FD, const CovariantThunkAdjustment& Adjustment, llvm::SmallVectorImpl<char> &Res) { - // FIXME: Hum, we might have to thunk these, fix. assert(!isa<CXXDestructorDecl>(FD) && - "Use mangleCXXDtor for destructor decls!"); + "No such thing as a covariant thunk for a destructor!"); // <special-name> ::= Tc <call-offset> <call-offset> <base encoding> // # base is the nominal target function of thunk @@ -1434,7 +1555,7 @@ void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, Mangler.mangleName(Type); } -void MangleContext::mangleCXXRtti(QualType Ty, +void MangleContext::mangleCXXRTTI(QualType Ty, llvm::SmallVectorImpl<char> &Res) { // <special-name> ::= TI <type> # typeinfo structure CXXNameMangler Mangler(*this, Res); @@ -1442,7 +1563,7 @@ void MangleContext::mangleCXXRtti(QualType Ty, Mangler.mangleType(Ty); } -void MangleContext::mangleCXXRttiName(QualType Ty, +void MangleContext::mangleCXXRTTIName(QualType Ty, llvm::SmallVectorImpl<char> &Res) { // <special-name> ::= TS <type> # typeinfo name (null terminated byte string) CXXNameMangler Mangler(*this, Res); diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h index 65b1d9f..8d96295 100644 --- a/lib/CodeGen/Mangle.h +++ b/lib/CodeGen/Mangle.h @@ -67,6 +67,9 @@ public: void mangleThunk(const FunctionDecl *FD, const ThunkAdjustment &ThisAdjustment, llvm::SmallVectorImpl<char> &); + void mangleCXXDtorThunk(const CXXDestructorDecl *D, CXXDtorType Type, + const ThunkAdjustment &ThisAdjustment, + llvm::SmallVectorImpl<char> &); void mangleCovariantThunk(const FunctionDecl *FD, const CovariantThunkAdjustment& Adjustment, llvm::SmallVectorImpl<char> &); @@ -76,8 +79,8 @@ public: void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, const CXXRecordDecl *Type, llvm::SmallVectorImpl<char> &); - void mangleCXXRtti(QualType T, llvm::SmallVectorImpl<char> &); - void mangleCXXRttiName(QualType T, llvm::SmallVectorImpl<char> &); + void mangleCXXRTTI(QualType T, llvm::SmallVectorImpl<char> &); + void mangleCXXRTTIName(QualType T, llvm::SmallVectorImpl<char> &); void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, llvm::SmallVectorImpl<char> &); void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp index 2bc6175..7be1ead 100644 --- a/lib/CodeGen/TargetABIInfo.cpp +++ b/lib/CodeGen/TargetABIInfo.cpp @@ -17,37 +17,37 @@ #include "clang/AST/RecordLayout.h" #include "llvm/Type.h" #include "llvm/ADT/Triple.h" -#include <cstdio> - +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace CodeGen; ABIInfo::~ABIInfo() {} void ABIArgInfo::dump() const { - fprintf(stderr, "(ABIArgInfo Kind="); + llvm::raw_ostream &OS = llvm::errs(); + OS << "(ABIArgInfo Kind="; switch (TheKind) { case Direct: - fprintf(stderr, "Direct"); + OS << "Direct"; break; case Extend: - fprintf(stderr, "Extend"); + OS << "Extend"; break; case Ignore: - fprintf(stderr, "Ignore"); + OS << "Ignore"; break; case Coerce: - fprintf(stderr, "Coerce Type="); - getCoerceToType()->print(llvm::errs()); + OS << "Coerce Type="; + getCoerceToType()->print(OS); break; case Indirect: - fprintf(stderr, "Indirect Align=%d", getIndirectAlign()); + OS << "Indirect Align=" << getIndirectAlign(); break; case Expand: - fprintf(stderr, "Expand"); + OS << "Expand"; break; } - fprintf(stderr, ")\n"); + OS << ")\n"; } static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); |