summaryrefslogtreecommitdiffstats
path: root/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/CGBlocks.cpp22
-rw-r--r--lib/CodeGen/CGBuiltin.cpp49
-rw-r--r--lib/CodeGen/CGCXX.cpp419
-rw-r--r--lib/CodeGen/CGCall.cpp5
-rw-r--r--lib/CodeGen/CGClass.cpp36
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp311
-rw-r--r--lib/CodeGen/CGDebugInfo.h9
-rw-r--r--lib/CodeGen/CGDecl.cpp286
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp211
-rw-r--r--lib/CodeGen/CGException.cpp542
-rw-r--r--lib/CodeGen/CGExpr.cpp104
-rw-r--r--lib/CodeGen/CGExprAgg.cpp19
-rw-r--r--lib/CodeGen/CGExprCXX.cpp189
-rw-r--r--lib/CodeGen/CGExprConstant.cpp6
-rw-r--r--lib/CodeGen/CGExprScalar.cpp119
-rw-r--r--lib/CodeGen/CGObjCMac.cpp62
-rw-r--r--lib/CodeGen/CGRTTI.cpp (renamed from lib/CodeGen/CGRtti.cpp)261
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp10
-rw-r--r--lib/CodeGen/CGVtable.cpp955
-rw-r--r--lib/CodeGen/CGVtable.h47
-rw-r--r--lib/CodeGen/CMakeLists.txt3
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp73
-rw-r--r--lib/CodeGen/CodeGenFunction.h119
-rw-r--r--lib/CodeGen/CodeGenModule.cpp88
-rw-r--r--lib/CodeGen/CodeGenModule.h49
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp8
-rw-r--r--lib/CodeGen/GlobalDecl.h15
-rw-r--r--lib/CodeGen/Mangle.cpp261
-rw-r--r--lib/CodeGen/Mangle.h7
-rw-r--r--lib/CodeGen/TargetABIInfo.cpp22
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);
OpenPOWER on IntegriCloud