Revert r184205 and associated patches while investigating issue with broken buildbot (possible interaction with LTO)

<rdar://problem/14209661>

llvm-svn: 184384
This commit is contained in:
Stephen Lin 2013-06-19 23:23:19 +00:00
parent 11b3ba7176
commit 19cee1871e
18 changed files with 276 additions and 263 deletions

View File

@ -97,12 +97,8 @@ public:
return *MangleCtx; return *MangleCtx;
} }
/// Returns true if the given constructor or destructor is one of the /// Returns true if the given instance method is one of the
/// kinds that the ABI says returns 'this' (only applies when called /// kinds that the ABI says returns 'this'.
/// non-virtually for destructors).
///
/// There currently is no way to indicate if a destructor returns 'this'
/// when called virtually, and code generation does not support the case.
virtual bool HasThisReturn(GlobalDecl GD) const { return false; } virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
/// Returns true if the given record type should be returned indirectly. /// Returns true if the given record type should be returned indirectly.
@ -218,10 +214,10 @@ public:
const CXXRecordDecl *BaseClassDecl) = 0; const CXXRecordDecl *BaseClassDecl) = 0;
/// Build the signature of the given constructor variant by adding /// Build the signature of the given constructor variant by adding
/// any required parameters. For convenience, ArgTys has been initialized /// any required parameters. For convenience, ResTy has been
/// with the type of 'this' and ResTy has been initialized with the type of /// initialized to 'void', and ArgTys has been initialized with the
/// 'this' if HasThisReturn(GlobalDecl(Ctor, T)) is true or 'void' otherwise /// type of 'this' (although this may be changed by the ABI) and
/// (although both may be changed by the ABI). /// will have the formal parameters added to it afterwards.
/// ///
/// If there are ever any ABIs where the implicit parameters are /// If there are ever any ABIs where the implicit parameters are
/// intermixed with the formal parameters, we can address those /// intermixed with the formal parameters, we can address those
@ -235,10 +231,9 @@ public:
const CXXRecordDecl *RD); const CXXRecordDecl *RD);
/// Build the signature of the given destructor variant by adding /// Build the signature of the given destructor variant by adding
/// any required parameters. For convenience, ArgTys has been initialized /// any required parameters. For convenience, ResTy has been
/// with the type of 'this' and ResTy has been initialized with the type of /// initialized to 'void' and ArgTys has been initialized with the
/// 'this' if HasThisReturn(GlobalDecl(Dtor, T)) is true or 'void' otherwise /// type of 'this' (although this may be changed by the ABI).
/// (although both may be changed by the ABI).
virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor, virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType T, CXXDtorType T,
CanQualType &ResTy, CanQualType &ResTy,
@ -249,8 +244,7 @@ public:
/// possibly some extra data for constructors and destructors. /// possibly some extra data for constructors and destructors.
/// ///
/// ABIs may also choose to override the return type, which has been /// ABIs may also choose to override the return type, which has been
/// initialized with the type of 'this' if HasThisReturn(CGF.CurGD) is true or /// initialized with the formal return type of the function.
/// the formal return type of the function otherwise.
virtual void BuildInstanceFunctionParams(CodeGenFunction &CGF, virtual void BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy, QualType &ResTy,
FunctionArgList &Params) = 0; FunctionArgList &Params) = 0;
@ -259,20 +253,21 @@ public:
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0; virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
/// Emit the constructor call. Return the function that is called. /// Emit the constructor call. Return the function that is called.
virtual void EmitConstructorCall(CodeGenFunction &CGF, virtual llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D, const CXXConstructorDecl *D,
CXXCtorType Type, CXXCtorType Type, bool ForVirtualBase,
bool ForVirtualBase, bool Delegating, bool Delegating,
llvm::Value *This, llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) = 0; CallExpr::const_arg_iterator ArgEnd) = 0;
/// Emit the ABI-specific virtual destructor call. /// Emit the ABI-specific virtual destructor call.
virtual void EmitVirtualDestructorCall(CodeGenFunction &CGF, virtual RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor, const CXXDestructorDecl *Dtor,
CXXDtorType DtorType, CXXDtorType DtorType,
SourceLocation CallLoc, SourceLocation CallLoc,
llvm::Value *This) = 0; ReturnValueSlot ReturnValue,
llvm::Value *This) = 0;
/// Emit any tables needed to implement virtual inheritance. For Itanium, /// Emit any tables needed to implement virtual inheritance. For Itanium,
/// this emits virtual table tables. For the MSVC++ ABI, this emits virtual /// this emits virtual table tables. For the MSVC++ ABI, this emits virtual

View File

@ -200,10 +200,7 @@ CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D,
CXXCtorType ctorKind) { CXXCtorType ctorKind) {
SmallVector<CanQualType, 16> argTypes; SmallVector<CanQualType, 16> argTypes;
argTypes.push_back(GetThisType(Context, D->getParent())); argTypes.push_back(GetThisType(Context, D->getParent()));
CanQualType resultType = Context.VoidTy;
GlobalDecl GD(D, ctorKind);
CanQualType resultType =
TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;
TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes); TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes);
@ -228,10 +225,7 @@ CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType dtorKind) { CXXDtorType dtorKind) {
SmallVector<CanQualType, 2> argTypes; SmallVector<CanQualType, 2> argTypes;
argTypes.push_back(GetThisType(Context, D->getParent())); argTypes.push_back(GetThisType(Context, D->getParent()));
CanQualType resultType = Context.VoidTy;
GlobalDecl GD(D, dtorKind);
CanQualType resultType =
TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;
TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes); TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes);
@ -1639,6 +1633,18 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
return store; return store;
} }
/// Check whether 'this' argument of a callsite matches 'this' of the caller.
static bool checkThisPointer(llvm::Value *ThisArg, llvm::Value *This) {
if (ThisArg == This)
return true;
// Check whether ThisArg is a bitcast of This.
llvm::BitCastInst *Bitcast;
if ((Bitcast = dyn_cast<llvm::BitCastInst>(ThisArg)) &&
Bitcast->getOperand(0) == This)
return true;
return false;
}
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
bool EmitRetDbgLoc) { bool EmitRetDbgLoc) {
// Functions with no result always return void. // Functions with no result always return void.
@ -1735,6 +1741,19 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
llvm_unreachable("Invalid ABI kind for return argument"); llvm_unreachable("Invalid ABI kind for return argument");
} }
// If this function returns 'this', the last instruction is a CallInst
// that returns 'this', and 'this' argument of the CallInst points to
// the same object as CXXThisValue, use the return value from the CallInst.
// We will not need to keep 'this' alive through the callsite. It also enables
// optimizations in the backend, such as tail call optimization.
if (CalleeWithThisReturn && CGM.getCXXABI().HasThisReturn(CurGD)) {
llvm::BasicBlock *IP = Builder.GetInsertBlock();
llvm::CallInst *Callsite;
if (!IP->empty() && (Callsite = dyn_cast<llvm::CallInst>(&IP->back())) &&
Callsite->getCalledFunction() == CalleeWithThisReturn &&
checkThisPointer(Callsite->getOperand(0), CXXThisValue))
RV = Builder.CreateBitCast(Callsite, RetAI.getCoerceToType());
}
llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid(); llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();
if (!RetDbgLoc.isUnknown()) if (!RetDbgLoc.isUnknown())
Ret->setDebugLoc(RetDbgLoc); Ret->setDebugLoc(RetDbgLoc);

View File

@ -1662,8 +1662,11 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
} }
// Non-trivial constructors are handled in an ABI-specific manner. // Non-trivial constructors are handled in an ABI-specific manner.
CGM.getCXXABI().EmitConstructorCall(*this, D, Type, ForVirtualBase, llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type,
Delegating, This, ArgBeg, ArgEnd); ForVirtualBase, Delegating, This, ArgBeg, ArgEnd);
if (CGM.getCXXABI().HasThisReturn(CurGD) &&
CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type)))
CalleeWithThisReturn = Callee;
} }
void void
@ -1755,6 +1758,9 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType); llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType), EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
Callee, ReturnValueSlot(), DelegateArgs, Ctor); Callee, ReturnValueSlot(), DelegateArgs, Ctor);
if (CGM.getCXXABI().HasThisReturn(CurGD) &&
CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType)))
CalleeWithThisReturn = Callee;
} }
namespace { namespace {
@ -1821,6 +1827,9 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This, EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
VTT, getContext().getPointerType(getContext().VoidPtrTy), VTT, getContext().getPointerType(getContext().VoidPtrTy),
0, 0); 0, 0);
if (CGM.getCXXABI().HasThisReturn(CurGD) &&
CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type)))
CalleeWithThisReturn = Callee;
} }
namespace { namespace {

View File

@ -280,15 +280,16 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
// We also don't emit a virtual call if the base expression has a record type // We also don't emit a virtual call if the base expression has a record type
// because then we know what the type is. // because then we know what the type is.
bool UseVirtualCall = CanUseVirtualCall && !DevirtualizedMethod; bool UseVirtualCall = CanUseVirtualCall && !DevirtualizedMethod;
llvm::Value *Callee;
llvm::Value *Callee;
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) { if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
assert(CE->arg_begin() == CE->arg_end() &&
"Destructor shouldn't have explicit parameters");
assert(ReturnValue.isNull() && "Destructor shouldn't have return value");
if (UseVirtualCall) { if (UseVirtualCall) {
CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor, Dtor_Complete, assert(CE->arg_begin() == CE->arg_end() &&
CE->getExprLoc(), This); "Virtual destructor shouldn't have explicit parameters");
return CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor,
Dtor_Complete,
CE->getExprLoc(),
ReturnValue, This);
} else { } else {
if (getLangOpts().AppleKext && if (getLangOpts().AppleKext &&
MD->isVirtual() && MD->isVirtual() &&
@ -301,16 +302,12 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
cast<CXXDestructorDecl>(DevirtualizedMethod); cast<CXXDestructorDecl>(DevirtualizedMethod);
Callee = CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty); Callee = CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty);
} }
EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
/*ImplicitParam=*/0, QualType(), 0, 0);
} }
return RValue::get(0); } else if (const CXXConstructorDecl *Ctor =
} dyn_cast<CXXConstructorDecl>(MD)) {
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
Callee = CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty); Callee = CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty);
} else if (UseVirtualCall) { } else if (UseVirtualCall) {
Callee = BuildVirtualCall(MD, This, Ty); Callee = BuildVirtualCall(MD, This, Ty);
} else { } else {
if (getLangOpts().AppleKext && if (getLangOpts().AppleKext &&
MD->isVirtual() && MD->isVirtual() &&
@ -1416,7 +1413,8 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
// FIXME: Provide a source location here. // FIXME: Provide a source location here.
CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting; CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
CGF.CGM.getCXXABI().EmitVirtualDestructorCall(CGF, Dtor, DtorType, CGF.CGM.getCXXABI().EmitVirtualDestructorCall(CGF, Dtor, DtorType,
SourceLocation(), Ptr); SourceLocation(),
ReturnValueSlot(), Ptr);
if (UseGlobalDelete) { if (UseGlobalDelete) {
CGF.PopCleanupBlock(); CGF.PopCleanupBlock();

View File

@ -287,9 +287,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
GlobalDecl GD, const ThunkInfo &Thunk) { GlobalDecl GD, const ThunkInfo &Thunk) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
QualType ResultType = FPT->getResultType();
QualType ThisType = MD->getThisType(getContext()); QualType ThisType = MD->getThisType(getContext());
QualType ResultType =
CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getResultType();
FunctionArgList FunctionArgs; FunctionArgList FunctionArgs;

View File

@ -42,7 +42,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
AutoreleaseResult(false), BlockInfo(0), BlockPointer(0), AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1), LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1),
FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0), FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false), DebugInfo(0), DisableDebugInfo(false), CalleeWithThisReturn(0),
DidCallStackSave(false),
IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
NumReturnExprs(0), NumSimpleReturnExprs(0), NumReturnExprs(0), NumSimpleReturnExprs(0),
CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0),
@ -661,12 +662,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
QualType ResTy = FD->getResultType(); QualType ResTy = FD->getResultType();
CurGD = GD; CurGD = GD;
const CXXMethodDecl *MD; if (isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isInstance())
if ((MD = dyn_cast<CXXMethodDecl>(FD)) && MD->isInstance()) {
if (CGM.getCXXABI().HasThisReturn(GD))
ResTy = MD->getThisType(getContext());
CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args); CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args);
}
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i)
Args.push_back(FD->getParamDecl(i)); Args.push_back(FD->getParamDecl(i));
@ -675,6 +672,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange(); if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
CurEHLocation = BodyRange.getEnd(); CurEHLocation = BodyRange.getEnd();
// CalleeWithThisReturn keeps track of the last callee inside this function
// that returns 'this'. Before starting the function, we set it to null.
CalleeWithThisReturn = 0;
// Emit the standard function prologue. // Emit the standard function prologue.
StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin()); StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
@ -726,6 +727,9 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// Emit the standard function epilogue. // Emit the standard function epilogue.
FinishFunction(BodyRange.getEnd()); FinishFunction(BodyRange.getEnd());
// CalleeWithThisReturn keeps track of the last callee inside this function
// that returns 'this'. After finishing the function, we set it to null.
CalleeWithThisReturn = 0;
// If we haven't marked the function nothrow through other means, do // If we haven't marked the function nothrow through other means, do
// a quick pass now to see if we can. // a quick pass now to see if we can.

View File

@ -798,6 +798,10 @@ private:
CGDebugInfo *DebugInfo; CGDebugInfo *DebugInfo;
bool DisableDebugInfo; bool DisableDebugInfo;
/// If the current function returns 'this', use the field to keep track of
/// the callee that returns 'this'.
llvm::Value *CalleeWithThisReturn;
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid /// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
/// calling llvm.stacksave for multiple VLAs in the same scope. /// calling llvm.stacksave for multiple VLAs in the same scope.
bool DidCallStackSave; bool DidCallStackSave;

View File

@ -722,14 +722,6 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
if (!IsIncompleteFunction) if (!IsIncompleteFunction)
SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F); SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F);
if (getCXXABI().HasThisReturn(GD)) {
assert(!F->arg_empty() &&
F->arg_begin()->getType()
->canLosslesslyBitCastTo(F->getReturnType()) &&
"unexpected this return");
F->addAttribute(1, llvm::Attribute::Returned);
}
// Only a few attributes are set on declarations; these may later be // Only a few attributes are set on declarations; these may later be
// overridden by a definition. // overridden by a definition.

View File

@ -119,17 +119,20 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF); void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
void EmitConstructorCall(CodeGenFunction &CGF, llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D, CXXCtorType Type, const CXXConstructorDecl *D,
bool ForVirtualBase, bool Delegating, CXXCtorType Type, bool ForVirtualBase,
bool Delegating,
llvm::Value *This, llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd); CallExpr::const_arg_iterator ArgEnd);
void EmitVirtualDestructorCall(CodeGenFunction &CGF, RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor, const CXXDestructorDecl *Dtor,
CXXDtorType DtorType, SourceLocation CallLoc, CXXDtorType DtorType,
llvm::Value *This); SourceLocation CallLoc,
ReturnValueSlot ReturnValue,
llvm::Value *This);
void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage, void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage,
const CXXRecordDecl *RD); const CXXRecordDecl *RD);
@ -165,11 +168,21 @@ class ARMCXXABI : public ItaniumCXXABI {
public: public:
ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {} ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {}
bool HasThisReturn(GlobalDecl GD) const { void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
return (isa<CXXConstructorDecl>(GD.getDecl()) || ( CXXCtorType T,
isa<CXXDestructorDecl>(GD.getDecl()) && CanQualType &ResTy,
GD.getDtorType() != Dtor_Deleting)); SmallVectorImpl<CanQualType> &ArgTys);
}
void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType T,
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys);
void BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
FunctionArgList &Params);
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy); void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy);
@ -181,6 +194,15 @@ public:
QualType ElementType); QualType ElementType);
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr, llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
CharUnits cookieSize); CharUnits cookieSize);
/// \brief Returns true if the given instance method is one of the
/// kinds that the ARM ABI says returns 'this'.
bool HasThisReturn(GlobalDecl GD) const {
const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(GD.getDecl());
if (!MD) return false;
return ((isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Deleting) ||
(isa<CXXConstructorDecl>(MD)));
}
}; };
} }
@ -735,14 +757,22 @@ void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
SmallVectorImpl<CanQualType> &ArgTys) { SmallVectorImpl<CanQualType> &ArgTys) {
ASTContext &Context = getContext(); ASTContext &Context = getContext();
// 'this' parameter is already there, as well as 'this' return if // 'this' is already there.
// HasThisReturn(GlobalDecl(Ctor, Type)) is true
// Check if we need to add a VTT parameter (which has type void **). // Check if we need to add a VTT parameter (which has type void **).
if (Type == Ctor_Base && Ctor->getParent()->getNumVBases() != 0) if (Type == Ctor_Base && Ctor->getParent()->getNumVBases() != 0)
ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
} }
/// The ARM ABI does the same as the Itanium ABI, but returns 'this'.
void ARMCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType Type,
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) {
ItaniumCXXABI::BuildConstructorSignature(Ctor, Type, ResTy, ArgTys);
ResTy = ArgTys[0];
}
/// The generic ABI passes 'this', plus a VTT if it's destroying a /// The generic ABI passes 'this', plus a VTT if it's destroying a
/// base subobject. /// base subobject.
void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
@ -751,14 +781,25 @@ void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
SmallVectorImpl<CanQualType> &ArgTys) { SmallVectorImpl<CanQualType> &ArgTys) {
ASTContext &Context = getContext(); ASTContext &Context = getContext();
// 'this' parameter is already there, as well as 'this' return if // 'this' is already there.
// HasThisReturn(GlobalDecl(Dtor, Type)) is true
// Check if we need to add a VTT parameter (which has type void **). // Check if we need to add a VTT parameter (which has type void **).
if (Type == Dtor_Base && Dtor->getParent()->getNumVBases() != 0) if (Type == Dtor_Base && Dtor->getParent()->getNumVBases() != 0)
ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
} }
/// The ARM ABI does the same as the Itanium ABI, but returns 'this'
/// for non-deleting destructors.
void ARMCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType Type,
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) {
ItaniumCXXABI::BuildDestructorSignature(Dtor, Type, ResTy, ArgTys);
if (Type != Dtor_Deleting)
ResTy = ArgTys[0];
}
void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy, QualType &ResTy,
FunctionArgList &Params) { FunctionArgList &Params) {
@ -782,6 +823,16 @@ void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
} }
} }
void ARMCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
FunctionArgList &Params) {
ItaniumCXXABI::BuildInstanceFunctionParams(CGF, ResTy, Params);
// Return 'this' from certain constructors and destructors.
if (HasThisReturn(CGF.CurGD))
ResTy = Params[0]->getType();
}
void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
/// Initialize the 'this' slot. /// Initialize the 'this' slot.
EmitThisParam(CGF); EmitThisParam(CGF);
@ -792,23 +843,21 @@ void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
= CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getVTTDecl(CGF)), = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getVTTDecl(CGF)),
"vtt"); "vtt");
} }
}
/// If this is a function that the ABI specifies returns 'this', initialize void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
/// the return slot to 'this' at the start of the function. ItaniumCXXABI::EmitInstanceFunctionProlog(CGF);
///
/// Unlike the setting of return types, this is done within the ABI /// Initialize the return slot to 'this' at the start of the
/// implementation instead of by clients of CGCXXABI because: /// function.
/// 1) getThisValue is currently protected
/// 2) in theory, an ABI could implement 'this' returns some other way;
/// HasThisReturn only specifies a contract, not the implementation
if (HasThisReturn(CGF.CurGD)) if (HasThisReturn(CGF.CurGD))
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue); CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
} }
void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF, llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D, const CXXConstructorDecl *D,
CXXCtorType Type, CXXCtorType Type, bool ForVirtualBase,
bool ForVirtualBase, bool Delegating, bool Delegating,
llvm::Value *This, llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) { CallExpr::const_arg_iterator ArgEnd) {
@ -818,15 +867,17 @@ void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
// FIXME: Provide a source location here. // FIXME: Provide a source location here.
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
This, VTT, VTTTy, ArgBeg, ArgEnd); VTT, VTTTy, ArgBeg, ArgEnd);
return Callee;
} }
void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor, const CXXDestructorDecl *Dtor,
CXXDtorType DtorType, CXXDtorType DtorType,
SourceLocation CallLoc, SourceLocation CallLoc,
llvm::Value *This) { ReturnValueSlot ReturnValue,
llvm::Value *This) {
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete); assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
const CGFunctionInfo *FInfo const CGFunctionInfo *FInfo
@ -834,8 +885,8 @@ void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo); llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, DtorType, This, Ty); llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, DtorType, This, Ty);
CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This, return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
/*ImplicitParam=*/0, QualType(), 0, 0); /*ImplicitParam=*/0, QualType(), 0, 0);
} }
void ItaniumCXXABI::EmitVirtualInheritanceTables( void ItaniumCXXABI::EmitVirtualInheritanceTables(

View File

@ -30,8 +30,6 @@ class MicrosoftCXXABI : public CGCXXABI {
public: public:
MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {} MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {}
bool HasThisReturn(GlobalDecl GD) const;
bool isReturnTypeIndirect(const CXXRecordDecl *RD) const { bool isReturnTypeIndirect(const CXXRecordDecl *RD) const {
// Structures that are not C++03 PODs are always indirect. // Structures that are not C++03 PODs are always indirect.
return !RD->isPOD(); return !RD->isPOD();
@ -76,17 +74,20 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF); void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
void EmitConstructorCall(CodeGenFunction &CGF, llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D, CXXCtorType Type, const CXXConstructorDecl *D,
bool ForVirtualBase, bool Delegating, CXXCtorType Type, bool ForVirtualBase,
bool Delegating,
llvm::Value *This, llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd); CallExpr::const_arg_iterator ArgEnd);
void EmitVirtualDestructorCall(CodeGenFunction &CGF, RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor, const CXXDestructorDecl *Dtor,
CXXDtorType DtorType, SourceLocation CallLoc, CXXDtorType DtorType,
llvm::Value *This); SourceLocation CallLoc,
ReturnValueSlot ReturnValue,
llvm::Value *This);
void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage, void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage,
const CXXRecordDecl *RD); const CXXRecordDecl *RD);
@ -129,6 +130,7 @@ public:
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
llvm::Value *allocPtr, llvm::Value *allocPtr,
CharUnits cookieSize); CharUnits cookieSize);
static bool needThisReturn(GlobalDecl GD);
private: private:
llvm::Constant *getZeroInt() { llvm::Constant *getZeroInt() {
@ -312,15 +314,19 @@ MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
return CGF.Builder.CreateNSWAdd(VBPtrOffset, VBPtrToNewBase); return CGF.Builder.CreateNSWAdd(VBPtrOffset, VBPtrToNewBase);
} }
bool MicrosoftCXXABI::HasThisReturn(GlobalDecl GD) const { bool MicrosoftCXXABI::needThisReturn(GlobalDecl GD) {
return isa<CXXConstructorDecl>(GD.getDecl()); const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
return isa<CXXConstructorDecl>(MD);
} }
void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType Type, CXXCtorType Type,
CanQualType &ResTy, CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) { SmallVectorImpl<CanQualType> &ArgTys) {
// 'this' parameter and 'this' return are already in place // 'this' is already in place
// Ctor returns this ptr
ResTy = ArgTys[0];
const CXXRecordDecl *Class = Ctor->getParent(); const CXXRecordDecl *Class = Ctor->getParent();
if (Class->getNumVBases()) { if (Class->getNumVBases()) {
@ -378,7 +384,6 @@ void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CanQualType &ResTy, CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) { SmallVectorImpl<CanQualType> &ArgTys) {
// 'this' is already in place // 'this' is already in place
// TODO: 'for base' flag // TODO: 'for base' flag
if (Type == Dtor_Deleting) { if (Type == Dtor_Deleting) {
@ -399,6 +404,9 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy, QualType &ResTy,
FunctionArgList &Params) { FunctionArgList &Params) {
BuildThisParam(CGF, Params); BuildThisParam(CGF, Params);
if (needThisReturn(CGF.CurGD)) {
ResTy = Params[0]->getType();
}
ASTContext &Context = getContext(); ASTContext &Context = getContext();
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl()); const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
@ -423,17 +431,9 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
EmitThisParam(CGF); EmitThisParam(CGF);
if (needThisReturn(CGF.CurGD)) {
/// If this is a function that the ABI specifies returns 'this', initialize
/// the return slot to 'this' at the start of the function.
///
/// Unlike the setting of return types, this is done within the ABI
/// implementation instead of by clients of CGCXXABI because:
/// 1) getThisValue is currently protected
/// 2) in theory, an ABI could implement 'this' returns some other way;
/// HasThisReturn only specifies a contract, not the implementation
if (HasThisReturn(CGF.CurGD))
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue); CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
}
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl()); const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) { if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
@ -455,10 +455,9 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
} }
} }
void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D, const CXXConstructorDecl *D,
CXXCtorType Type, CXXCtorType Type, bool ForVirtualBase,
bool ForVirtualBase,
bool Delegating, bool Delegating,
llvm::Value *This, llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgBeg,
@ -475,14 +474,17 @@ void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
// FIXME: Provide a source location here. // FIXME: Provide a source location here.
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
ImplicitParam, ImplicitParamTy, ArgBeg, ArgEnd); ImplicitParam, ImplicitParamTy,
ArgBeg, ArgEnd);
return Callee;
} }
void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor, const CXXDestructorDecl *Dtor,
CXXDtorType DtorType, CXXDtorType DtorType,
SourceLocation CallLoc, SourceLocation CallLoc,
llvm::Value *This) { ReturnValueSlot ReturnValue,
llvm::Value *This) {
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete); assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
// We have only one destructor in the vftable but can get both behaviors // We have only one destructor in the vftable but can get both behaviors
@ -497,8 +499,8 @@ void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
= llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(CGF.getLLVMContext()), = llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(CGF.getLLVMContext()),
DtorType == Dtor_Deleting); DtorType == Dtor_Deleting);
CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This, return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
ImplicitParam, Context.BoolTy, 0, 0); ImplicitParam, Context.BoolTy, 0, 0);
} }
const VBTableVector & const VBTableVector &

View File

@ -52,19 +52,19 @@ namespace test1 {
a.bar(); a.bar();
} }
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* returned %this, i32 %i) unnamed_addr // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* %this, i32 %i) unnamed_addr
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]] // CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
// CHECK: {{%.*}} = call [[A]]* @_ZN5test11AC2Ei( // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AC2Ei(
// CHECK: ret [[A]]* [[THIS1]] // CHECK: ret [[A]]* [[THIS2]]
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* returned %this) unnamed_addr // CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]] // CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
// CHECK: {{%.*}} = call [[A]]* @_ZN5test11AD2Ev( // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AD2Ev(
// CHECK: ret [[A]]* [[THIS1]] // CHECK: ret [[A]]* [[THIS2]]
} }
// Awkward virtual cases. // Awkward virtual cases.

View File

@ -1,119 +1,60 @@
//RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-unknown-linux | FileCheck --check-prefix=CHECKGEN %s //RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck %s
//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck --check-prefix=CHECKARM %s
//RUN: %clang_cc1 %s -emit-llvm -o - -DPR12784_WORKAROUND -triple=x86_64-pc-win32 -cxx-abi microsoft | FileCheck --check-prefix=CHECKMS %s
// FIXME: Add checks to ensure that Microsoft destructors do not return 'this' // For constructors/desctructors that return 'this', if there exists a callsite
// once PR12784 is resolved // that returns 'this' and is immediately before the return instruction, make
// sure we are using the return value from the callsite.
// rdar://12818789
// Make sure we attach the 'returned' attribute to the 'this' parameter of // CHECK: define linkonce_odr [[A:%.*]] @_ZN11ObjectCacheC1Ev([[A]] %this) unnamed_addr
// constructors and destructors which return this (and only these cases) // CHECK: [[THIS1:%.*]] = call [[A]] @_ZN11ObjectCacheC2Ev(
// CHECK-NEXT: ret [[A]] [[THIS1]]
class A { // CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheEC1EPS0_MS0_FvPS1_E([[A]] %this
// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheEC2EPS0_MS0_FvPS1_E(
// CHECK-NEXT: ret [[A]] [[THIS1]]
// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED1Ev([[A]] %this) unnamed_addr
// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheED2Ev(
// CHECK-NEXT: ret [[A]] [[THIS1]]
// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED2Ev([[A]] %this) unnamed_addr
// CHECK: [[THIS1:%.*]] = call [[B:%.*]] @_ZN9TimerBaseD2Ev(
// CHECK-NEXT: [[THIS2:%.*]] = bitcast [[B]] [[THIS1]] to [[A]]
// CHECK-NEXT: ret [[A]] [[THIS2]]
class TimerBase {
public: public:
A(); TimerBase();
~A(); virtual ~TimerBase();
};
template <typename TimerFiredClass> class Timer : public TimerBase {
public:
typedef void (TimerFiredClass::*TimerFiredFunction)(Timer*);
Timer(TimerFiredClass* o, TimerFiredFunction f)
: m_object(o), m_function(f) { }
private: private:
int x_; virtual void fired() { (m_object->*m_function)(this); }
TimerFiredClass* m_object;
TimerFiredFunction m_function;
}; };
class B : public A { class ObjectCache {
public: public:
B(int *i); explicit ObjectCache();
~B(); ~ObjectCache();
private: private:
int *i_; Timer<ObjectCache> m_notificationPostTimer;
}; };
B::B(int *i) : i_(i) { } inline ObjectCache::ObjectCache() : m_notificationPostTimer(this, 0) { }
#ifndef PR12784_WORKAROUND inline ObjectCache::~ObjectCache() { }
B::~B() { }
#endif
// CHECKGEN: define void @_ZN1BC1EPi(%class.B* %this, i32* %i) ObjectCache *test() {
// CHECKGEN: define void @_ZN1BC2EPi(%class.B* %this, i32* %i) ObjectCache *dd = new ObjectCache();
// CHECKGEN: define void @_ZN1BD1Ev(%class.B* %this) return dd;
// CHECKGEN: define void @_ZN1BD2Ev(%class.B* %this)
// CHECKARM: define %class.B* @_ZN1BC1EPi(%class.B* returned %this, i32* %i)
// CHECKARM: define %class.B* @_ZN1BC2EPi(%class.B* returned %this, i32* %i)
// CHECKARM: define %class.B* @_ZN1BD1Ev(%class.B* returned %this)
// CHECKARM: define %class.B* @_ZN1BD2Ev(%class.B* returned %this)
// CHECKMS: define %class.B* @"\01??0B@@QEAA@PEAH@Z"(%class.B* returned %this, i32* %i)
class C : public A, public B {
public:
C(int *i, char *c);
virtual ~C();
private:
char *c_;
};
C::C(int *i, char *c) : B(i), c_(c) { }
#ifndef PR12784_WORKAROUND
C::~C() { }
#endif
// CHECKGEN: define void @_ZN1CC1EPiPc(%class.C* %this, i32* %i, i8* %c)
// CHECKGEN: define void @_ZN1CC2EPiPc(%class.C* %this, i32* %i, i8* %c)
// CHECKGEN: define void @_ZN1CD0Ev(%class.C* %this)
// CHECKGEN: define void @_ZN1CD1Ev(%class.C* %this)
// CHECKGEN: define void @_ZN1CD2Ev(%class.C* %this)
// CHECKARM: define %class.C* @_ZN1CC1EPiPc(%class.C* returned %this, i32* %i, i8* %c)
// CHECKARM: define %class.C* @_ZN1CC2EPiPc(%class.C* returned %this, i32* %i, i8* %c)
// CHECKARM: define void @_ZN1CD0Ev(%class.C* %this)
// CHECKARM: define %class.C* @_ZN1CD1Ev(%class.C* returned %this)
// CHECKARM: define %class.C* @_ZN1CD2Ev(%class.C* returned %this)
// CHECKMS: define %class.C* @"\01??0C@@QEAA@PEAHPEAD@Z"(%class.C* returned %this, i32* %i, i8* %c)
class D : public virtual A {
public:
D();
~D();
};
#ifndef PR12784_WORKAROUND
D::D() { }
D::~D() { }
#endif
// CHECKGEN: define void @_ZN1DC1Ev(%class.D* %this)
// CHECKGEN: define void @_ZN1DC2Ev(%class.D* %this, i8** %vtt)
// CHECKGEN: define void @_ZN1DD1Ev(%class.D* %this)
// CHECKGEN: define void @_ZN1DD2Ev(%class.D* %this, i8** %vtt)
// CHECKARM: define %class.D* @_ZN1DC1Ev(%class.D* returned %this)
// CHECKARM: define %class.D* @_ZN1DC2Ev(%class.D* returned %this, i8** %vtt)
// CHECKARM: define %class.D* @_ZN1DD1Ev(%class.D* returned %this)
// CHECKARM: define %class.D* @_ZN1DD2Ev(%class.D* returned %this, i8** %vtt)
class E {
public:
E();
virtual ~E();
};
E* gete();
void test_destructor() {
const E& e1 = E();
E* e2 = gete();
e2->~E();
} }
// CHECKARM: define void @_Z15test_destructorv()
// Verify that virtual calls to destructors are not marked with a 'returned'
// this parameter at the call site...
// CHECKARM: [[VFN:%.*]] = getelementptr inbounds %class.E* (%class.E*)**
// CHECKARM: [[THUNK:%.*]] = load %class.E* (%class.E*)** [[VFN]]
// CHECKARM: call %class.E* [[THUNK]](%class.E* %
// ...but static calls create declarations with 'returned' this
// CHECKARM: {{%.*}} = call %class.E* @_ZN1ED1Ev(%class.E* %
// CHECKARM: declare %class.E* @_ZN1ED1Ev(%class.E* returned)

View File

@ -21,7 +21,7 @@ namespace no_elide_base {
Derived(const Other &O); Derived(const Other &O);
}; };
// CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* returned %this, %"struct.no_elide_base::Other"* %O) unnamed_addr // CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* %this, %"struct.no_elide_base::Other"* %O) unnamed_addr
Derived::Derived(const Other &O) Derived::Derived(const Other &O)
// CHECK: call {{.*}} @_ZNK13no_elide_base5OthercvNS_4BaseEEv // CHECK: call {{.*}} @_ZNK13no_elide_base5OthercvNS_4BaseEEv
// CHECK: call {{.*}} @_ZN13no_elide_base4BaseC2ERKS0_ // CHECK: call {{.*}} @_ZN13no_elide_base4BaseC2ERKS0_

View File

@ -3,5 +3,5 @@
struct A { virtual void a(); }; struct A { virtual void a(); };
A x(A& y) { return y; } A x(A& y) { return y; }
// CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* {{.*}}%this, %struct.A*) unnamed_addr // CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* %this, %struct.A*) unnamed_addr
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)

View File

@ -5,7 +5,6 @@ struct B { A<int> x; };
void a() { void a() {
B b; B b;
} }
// CHECK: call {{.*}} @_ZN1BC1Ev // CHECK: call {{.*}} @_ZN1BC1Ev
// CHECK: define linkonce_odr {{.*}} @_ZN1BC1Ev(%struct.B* {{.*}}%this) unnamed_addr // CHECK: define linkonce_odr {{.*}} @_ZN1BC1Ev(%struct.B* %this) unnamed_addr
// CHECK: call {{.*}} @_ZN1AIiEC1Ev // CHECK: call {{.*}} @_ZN1AIiEC1Ev

View File

@ -82,7 +82,7 @@ namespace test7 {
X(U*, typename int_c<(meta<T>::value + meta<U>::value)>::type *) { } X(U*, typename int_c<(meta<T>::value + meta<U>::value)>::type *) { }
}; };
// CHECK: define weak_odr {{.*}} @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsr4metaIS3_EE5valueEE4typeE( // CHECK: define weak_odr {{.*}} @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsr4metaIS3_EE5valueEE4typeE(%"struct.test7::X"* %this, double*, float*) unnamed_addr
template X<int>::X(double*, float*); template X<int>::X(double*, float*);
} }
@ -101,7 +101,7 @@ namespace test8 {
template<typename T> template<typename T>
void f(int_c<meta<T>::type::value>) { } void f(int_c<meta<T>::type::value>) { }
// CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsr4metaIT_E4typeE5valueEEE( // CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsr4metaIT_E4typeE5valueEEE
template void f<int>(int_c<sizeof(int)>); template void f<int>(int_c<sizeof(int)>);
} }

View File

@ -15,7 +15,7 @@ class A {
void no_constructor_destructor_infinite_recursion() { void no_constructor_destructor_infinite_recursion() {
A a; A a;
// CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* returned %this) // CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* %this)
// CHECK: [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca %"class.basic::A"*, align 4 // CHECK: [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca %"class.basic::A"*, align 4
// CHECK-NEXT: store %"class.basic::A"* %this, %"class.basic::A"** [[THIS_ADDR]], align 4 // CHECK-NEXT: store %"class.basic::A"* %this, %"class.basic::A"** [[THIS_ADDR]], align 4
// CHECK-NEXT: [[T1:%[.0-9A-Z_a-z]+]] = load %"class.basic::A"** [[THIS_ADDR]] // CHECK-NEXT: [[T1:%[.0-9A-Z_a-z]+]] = load %"class.basic::A"** [[THIS_ADDR]]
@ -34,7 +34,7 @@ struct B {
// Tests that we can define constructors outside the class (PR12784). // Tests that we can define constructors outside the class (PR12784).
B::B() { B::B() {
// CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* returned %this) // CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* %this)
// CHECK: ret // CHECK: ret
} }
@ -136,7 +136,7 @@ struct B : A {
}; };
B::B() { B::B() {
// CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* returned %this) // CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* %this)
// CHECK: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}}) // CHECK: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
// CHECK: ret // CHECK: ret
} }
@ -146,7 +146,7 @@ struct C : virtual A {
}; };
C::C() { C::C() {
// CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* returned %this, i32 %is_most_derived) // CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %this, i32 %is_most_derived)
// TODO: make sure this works in the Release build too; // TODO: make sure this works in the Release build too;
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4 // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]] // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
@ -179,7 +179,7 @@ struct D : C {
}; };
D::D() { D::D() {
// CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* returned %this, i32 %is_most_derived) unnamed_addr // CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* %this, i32 %is_most_derived) unnamed_addr
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4 // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]] // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
// CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0 // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
@ -204,7 +204,7 @@ struct E : virtual C {
}; };
E::E() { E::E() {
// CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* returned %this, i32 %is_most_derived) unnamed_addr // CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* %this, i32 %is_most_derived) unnamed_addr
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4 // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]] // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
// CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0 // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0

View File

@ -18,34 +18,34 @@ int main() {
// basic_iostream's complete dtor calls its base dtor, then its // basic_iostream's complete dtor calls its base dtor, then its
// virtual base's dtor. // virtual base's dtor.
// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* {{.*}}%this) unnamed_addr // CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* %this) unnamed_addr
// CHECK: call {{.*}} @_ZN14basic_iostreamIcED2Ev // CHECK: call {{.*}} @_ZN14basic_iostreamIcED2Ev
// CHECK: call {{.*}} @_ZN9basic_iosD2Ev // CHECK: call {{.*}} @_ZN9basic_iosD2Ev
// basic_iostream's base dtor calls its non-virtual base dtor. // basic_iostream's base dtor calls its non-virtual base dtor.
// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* {{.*}}%this, i8** %vtt) unnamed_addr // CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* %this, i8** %vtt) unnamed_addr
// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev // CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev
// CHECK: } // CHECK: }
// basic_iostream's deleting dtor calls its complete dtor, then // basic_iostream's deleting dtor calls its complete dtor, then
// operator delete(). // operator delete().
// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* {{.*}}%this) unnamed_addr // CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* %this) unnamed_addr
// CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev // CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev
// CHECK: call {{.*}} @_ZdlPv // CHECK: call {{.*}} @_ZdlPv
// basic_istream's complete dtor calls the base dtor, // basic_istream's complete dtor calls the base dtor,
// then its virtual base's base dtor. // then its virtual base's base dtor.
// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* {{.*}}%this) unnamed_addr // CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* %this) unnamed_addr
// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev // CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev
// CHECK: call {{.*}} @_ZN9basic_iosD2Ev // CHECK: call {{.*}} @_ZN9basic_iosD2Ev
// basic_istream's deleting dtor calls the complete dtor, then // basic_istream's deleting dtor calls the complete dtor, then
// operator delete(). // operator delete().
// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* {{.*}}%this) unnamed_addr // CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* %this) unnamed_addr
// CHECK: call {{.*}} @_ZN13basic_istreamIcED1Ev // CHECK: call {{.*}} @_ZN13basic_istreamIcED1Ev
// CHECK: call {{.*}} @_ZdlPv // CHECK: call {{.*}} @_ZdlPv
// basic_istream's base dtor is a no-op. // basic_istream's base dtor is a no-op.
// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* {{.*}}%this, i8** %vtt) unnamed_addr // CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* %this, i8** %vtt) unnamed_addr
// CHECK-NOT: call // CHECK-NOT: call
// CHECK: } // CHECK: }