<div dir="ltr">On Tue, Jun 18, 2013 at 10:00 AM, Stephen Lin <span dir="ltr"><<a href="mailto:stephenwlin@gmail.com" target="_blank">stephenwlin@gmail.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: stephenwlin<br>
Date: Tue Jun 18 12:00:49 2013<br>
New Revision: 184205<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=184205&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=184205&view=rev</a><br>
Log:<br>
CodeGen: Have 'this'-returning constructors and destructors to take advantage of the new backend 'returned' attribute.<br></blockquote><div><br></div><div>The implementation of the ARM ABI 'implicit return this from constructors' behavior has caused PR17759. I'm not sure if your patches caused this or if it's pre-existing; interested in investigating? =)</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
The backend will now use the generic 'returned' attribute to form tail calls where possible, as well as avoid save-restores of 'this' in some cases (specifically the cases that matter for the ARM C++ ABI).<br>
<br>
This patch also reverts a prior front-end only partial implementation of these optimizations, since it's no longer required.<br>
<br>
Modified:<br>
cfe/trunk/lib/CodeGen/CGCXXABI.h<br>
cfe/trunk/lib/CodeGen/CGCall.cpp<br>
cfe/trunk/lib/CodeGen/CGClass.cpp<br>
cfe/trunk/lib/CodeGen/CGVTables.cpp<br>
cfe/trunk/lib/CodeGen/CodeGenFunction.cpp<br>
cfe/trunk/lib/CodeGen/CodeGenFunction.h<br>
cfe/trunk/lib/CodeGen/CodeGenModule.cpp<br>
cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp<br>
cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp<br>
cfe/trunk/test/CodeGenCXX/arm.cpp<br>
cfe/trunk/test/CodeGenCXX/constructor-destructor-return-this.cpp<br>
cfe/trunk/test/CodeGenCXX/copy-constructor-elim-2.cpp<br>
cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=184205&r1=184204&r2=184205&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=184205&r1=184204&r2=184205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)<br>
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Tue Jun 18 12:00:49 2013<br>
@@ -97,8 +97,12 @@ public:<br>
return *MangleCtx;<br>
}<br>
<br>
- /// Returns true if the given instance method is one of the<br>
- /// kinds that the ABI says returns 'this'.<br>
+ /// Returns true if the given constructor or destructor is one of the<br>
+ /// kinds that the ABI says returns 'this' (only applies when called<br>
+ /// non-virtually for destructors).<br>
+ ///<br>
+ /// There currently is no way to indicate if a destructor returns 'this'<br>
+ /// when called virtually, and code generation does not support the case.<br>
virtual bool HasThisReturn(GlobalDecl GD) const { return false; }<br>
<br>
/// Returns true if the given record type should be returned indirectly.<br>
@@ -214,10 +218,10 @@ public:<br>
const CXXRecordDecl *BaseClassDecl) = 0;<br>
<br>
/// Build the signature of the given constructor variant by adding<br>
- /// any required parameters. For convenience, ResTy has been<br>
- /// initialized to 'void', and ArgTys has been initialized with the<br>
- /// type of 'this' (although this may be changed by the ABI) and<br>
- /// will have the formal parameters added to it afterwards.<br>
+ /// any required parameters. For convenience, ArgTys has been initialized<br>
+ /// with the type of 'this' and ResTy has been initialized with the type of<br>
+ /// 'this' if HasThisReturn(GlobalDecl(Ctor, T)) is true or 'void' otherwise<br>
+ /// (although both may be changed by the ABI).<br>
///<br>
/// If there are ever any ABIs where the implicit parameters are<br>
/// intermixed with the formal parameters, we can address those<br>
@@ -230,9 +234,10 @@ public:<br>
virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF);<br>
<br>
/// Build the signature of the given destructor variant by adding<br>
- /// any required parameters. For convenience, ResTy has been<br>
- /// initialized to 'void' and ArgTys has been initialized with the<br>
- /// type of 'this' (although this may be changed by the ABI).<br>
+ /// any required parameters. For convenience, ArgTys has been initialized<br>
+ /// with the type of 'this' and ResTy has been initialized with the type of<br>
+ /// 'this' if HasThisReturn(GlobalDecl(Dtor, T)) is true or 'void' otherwise<br>
+ /// (although both may be changed by the ABI).<br>
virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor,<br>
CXXDtorType T,<br>
CanQualType &ResTy,<br>
@@ -243,7 +248,8 @@ public:<br>
/// possibly some extra data for constructors and destructors.<br>
///<br>
/// ABIs may also choose to override the return type, which has been<br>
- /// initialized with the formal return type of the function.<br>
+ /// initialized with the type of 'this' if HasThisReturn(CGF.CurGD) is true or<br>
+ /// the formal return type of the function otherwise.<br>
virtual void BuildInstanceFunctionParams(CodeGenFunction &CGF,<br>
QualType &ResTy,<br>
FunctionArgList &Params) = 0;<br>
@@ -252,13 +258,14 @@ public:<br>
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;<br>
<br>
/// Emit the constructor call. Return the function that is called.<br>
- virtual llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,<br>
- const CXXConstructorDecl *D,<br>
- CXXCtorType Type, bool ForVirtualBase,<br>
- bool Delegating,<br>
- llvm::Value *This,<br>
- CallExpr::const_arg_iterator ArgBeg,<br>
- CallExpr::const_arg_iterator ArgEnd) = 0;<br>
+ virtual RValue EmitConstructorCall(CodeGenFunction &CGF,<br>
+ const CXXConstructorDecl *D,<br>
+ CXXCtorType Type,<br>
+ bool ForVirtualBase, bool Delegating,<br>
+ ReturnValueSlot ReturnValue,<br>
+ llvm::Value *This,<br>
+ CallExpr::const_arg_iterator ArgBeg,<br>
+ CallExpr::const_arg_iterator ArgEnd) = 0;<br>
<br>
/// Emit the ABI-specific virtual destructor call.<br>
virtual RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGCall.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=184205&r1=184204&r2=184205&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=184205&r1=184204&r2=184205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Tue Jun 18 12:00:49 2013<br>
@@ -200,7 +200,10 @@ CodeGenTypes::arrangeCXXConstructorDecla<br>
CXXCtorType ctorKind) {<br>
SmallVector<CanQualType, 16> argTypes;<br>
argTypes.push_back(GetThisType(Context, D->getParent()));<br>
- CanQualType resultType = Context.VoidTy;<br>
+<br>
+ GlobalDecl GD(D, ctorKind);<br>
+ CanQualType resultType =<br>
+ TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;<br>
<br>
TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes);<br>
<br>
@@ -225,7 +228,10 @@ CodeGenTypes::arrangeCXXDestructor(const<br>
CXXDtorType dtorKind) {<br>
SmallVector<CanQualType, 2> argTypes;<br>
argTypes.push_back(GetThisType(Context, D->getParent()));<br>
- CanQualType resultType = Context.VoidTy;<br>
+<br>
+ GlobalDecl GD(D, dtorKind);<br>
+ CanQualType resultType =<br>
+ TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;<br>
<br>
TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes);<br>
<br>
@@ -1633,18 +1639,6 @@ static llvm::StoreInst *findDominatingSt<br>
return store;<br>
}<br>
<br>
-/// Check whether 'this' argument of a callsite matches 'this' of the caller.<br>
-static bool checkThisPointer(llvm::Value *ThisArg, llvm::Value *This) {<br>
- if (ThisArg == This)<br>
- return true;<br>
- // Check whether ThisArg is a bitcast of This.<br>
- llvm::BitCastInst *Bitcast;<br>
- if ((Bitcast = dyn_cast<llvm::BitCastInst>(ThisArg)) &&<br>
- Bitcast->getOperand(0) == This)<br>
- return true;<br>
- return false;<br>
-}<br>
-<br>
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,<br>
bool EmitRetDbgLoc) {<br>
// Functions with no result always return void.<br>
@@ -1741,19 +1735,6 @@ void CodeGenFunction::EmitFunctionEpilog<br>
llvm_unreachable("Invalid ABI kind for return argument");<br>
}<br>
<br>
- // If this function returns 'this', the last instruction is a CallInst<br>
- // that returns 'this', and 'this' argument of the CallInst points to<br>
- // the same object as CXXThisValue, use the return value from the CallInst.<br>
- // We will not need to keep 'this' alive through the callsite. It also enables<br>
- // optimizations in the backend, such as tail call optimization.<br>
- if (CalleeWithThisReturn && CGM.getCXXABI().HasThisReturn(CurGD)) {<br>
- llvm::BasicBlock *IP = Builder.GetInsertBlock();<br>
- llvm::CallInst *Callsite;<br>
- if (!IP->empty() && (Callsite = dyn_cast<llvm::CallInst>(&IP->back())) &&<br>
- Callsite->getCalledFunction() == CalleeWithThisReturn &&<br>
- checkThisPointer(Callsite->getOperand(0), CXXThisValue))<br>
- RV = Builder.CreateBitCast(Callsite, RetAI.getCoerceToType());<br>
- }<br>
llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();<br>
if (!RetDbgLoc.isUnknown())<br>
Ret->setDebugLoc(RetDbgLoc);<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGClass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=184205&r1=184204&r2=184205&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=184205&r1=184204&r2=184205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Tue Jun 18 12:00:49 2013<br>
@@ -1661,11 +1661,9 @@ CodeGenFunction::EmitCXXConstructorCall(<br>
}<br>
<br>
// Non-trivial constructors are handled in an ABI-specific manner.<br>
- llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type,<br>
- ForVirtualBase, Delegating, This, ArgBeg, ArgEnd);<br>
- if (CGM.getCXXABI().HasThisReturn(CurGD) &&<br>
- CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type)))<br>
- CalleeWithThisReturn = Callee;<br>
+ CGM.getCXXABI().EmitConstructorCall(*this, D, Type,<br>
+ ForVirtualBase, Delegating,<br>
+ ReturnValueSlot(), This, ArgBeg, ArgEnd);<br>
}<br>
<br>
void<br>
@@ -1757,9 +1755,6 @@ CodeGenFunction::EmitDelegateCXXConstruc<br>
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);<br>
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),<br>
Callee, ReturnValueSlot(), DelegateArgs, Ctor);<br>
- if (CGM.getCXXABI().HasThisReturn(CurGD) &&<br>
- CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType)))<br>
- CalleeWithThisReturn = Callee;<br>
}<br>
<br>
namespace {<br>
@@ -1826,9 +1821,6 @@ void CodeGenFunction::EmitCXXDestructorC<br>
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,<br>
VTT, getContext().getPointerType(getContext().VoidPtrTy),<br>
0, 0);<br>
- if (CGM.getCXXABI().HasThisReturn(CurGD) &&<br>
- CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type)))<br>
- CalleeWithThisReturn = Callee;<br>
}<br>
<br>
namespace {<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=184205&r1=184204&r2=184205&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=184205&r1=184204&r2=184205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGVTables.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGVTables.cpp Tue Jun 18 12:00:49 2013<br>
@@ -287,8 +287,9 @@ void CodeGenFunction::GenerateThunk(llvm<br>
GlobalDecl GD, const ThunkInfo &Thunk) {<br>
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());<br>
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();<br>
- QualType ResultType = FPT->getResultType();<br>
QualType ThisType = MD->getThisType(getContext());<br>
+ QualType ResultType =<br>
+ CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getResultType();<br>
<br>
FunctionArgList FunctionArgs;<br>
<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=184205&r1=184204&r2=184205&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=184205&r1=184204&r2=184205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Tue Jun 18 12:00:49 2013<br>
@@ -42,8 +42,7 @@ CodeGenFunction::CodeGenFunction(CodeGen<br>
AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),<br>
LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1),<br>
FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),<br>
- DebugInfo(0), DisableDebugInfo(false), CalleeWithThisReturn(0),<br>
- DidCallStackSave(false),<br>
+ DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),<br>
IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),<br>
NumReturnExprs(0), NumSimpleReturnExprs(0),<br>
CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0),<br>
@@ -662,8 +661,12 @@ void CodeGenFunction::GenerateCode(Globa<br>
QualType ResTy = FD->getResultType();<br>
<br>
CurGD = GD;<br>
- if (isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isInstance())<br>
+ const CXXMethodDecl *MD;<br>
+ if ((MD = dyn_cast<CXXMethodDecl>(FD)) && MD->isInstance()) {<br>
+ if (CGM.getCXXABI().HasThisReturn(GD))<br>
+ ResTy = MD->getThisType(getContext());<br>
CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args);<br>
+ }<br>
<br>
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i)<br>
Args.push_back(FD->getParamDecl(i));<br>
@@ -672,10 +675,6 @@ void CodeGenFunction::GenerateCode(Globa<br>
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();<br>
CurEHLocation = BodyRange.getEnd();<br>
<br>
- // CalleeWithThisReturn keeps track of the last callee inside this function<br>
- // that returns 'this'. Before starting the function, we set it to null.<br>
- CalleeWithThisReturn = 0;<br>
-<br>
// Emit the standard function prologue.<br>
StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());<br>
<br>
@@ -727,9 +726,6 @@ void CodeGenFunction::GenerateCode(Globa<br>
<br>
// Emit the standard function epilogue.<br>
FinishFunction(BodyRange.getEnd());<br>
- // CalleeWithThisReturn keeps track of the last callee inside this function<br>
- // that returns 'this'. After finishing the function, we set it to null.<br>
- CalleeWithThisReturn = 0;<br>
<br>
// If we haven't marked the function nothrow through other means, do<br>
// a quick pass now to see if we can.<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=184205&r1=184204&r2=184205&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=184205&r1=184204&r2=184205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)<br>
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Jun 18 12:00:49 2013<br>
@@ -798,10 +798,6 @@ private:<br>
CGDebugInfo *DebugInfo;<br>
bool DisableDebugInfo;<br>
<br>
- /// If the current function returns 'this', use the field to keep track of<br>
- /// the callee that returns 'this'.<br>
- llvm::Value *CalleeWithThisReturn;<br>
-<br>
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid<br>
/// calling llvm.stacksave for multiple VLAs in the same scope.<br>
bool DidCallStackSave;<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=184205&r1=184204&r2=184205&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=184205&r1=184204&r2=184205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Tue Jun 18 12:00:49 2013<br>
@@ -717,6 +717,14 @@ void CodeGenModule::SetFunctionAttribute<br>
if (!IsIncompleteFunction)<br>
SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F);<br>
<br>
+ if (getCXXABI().HasThisReturn(GD)) {<br>
+ llvm::Type *RetTy = F->getReturnType();<br>
+ assert(!F->arg_empty() &&<br>
+ F->arg_begin()->getType()->canLosslesslyBitCastTo(RetTy) &&<br>
+ "unexpected this return");<br>
+ F->addAttribute(1, llvm::Attribute::Returned);<br>
+ }<br>
+<br>
// Only a few attributes are set on declarations; these may later be<br>
// overridden by a definition.<br>
<br>
<br>
Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=184205&r1=184204&r2=184205&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=184205&r1=184204&r2=184205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue Jun 18 12:00:49 2013<br>
@@ -119,13 +119,14 @@ public:<br>
<br>
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);<br>
<br>
- llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,<br>
- const CXXConstructorDecl *D,<br>
- CXXCtorType Type, bool ForVirtualBase,<br>
- bool Delegating,<br>
- llvm::Value *This,<br>
- CallExpr::const_arg_iterator ArgBeg,<br>
- CallExpr::const_arg_iterator ArgEnd);<br>
+ RValue EmitConstructorCall(CodeGenFunction &CGF,<br>
+ const CXXConstructorDecl *D,<br>
+ CXXCtorType Type,<br>
+ bool ForVirtualBase, bool Delegating,<br>
+ ReturnValueSlot ReturnValue,<br>
+ llvm::Value *This,<br>
+ CallExpr::const_arg_iterator ArgBeg,<br>
+ CallExpr::const_arg_iterator ArgEnd);<br>
<br>
RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,<br>
const CXXDestructorDecl *Dtor,<br>
@@ -165,21 +166,11 @@ class ARMCXXABI : public ItaniumCXXABI {<br>
public:<br>
ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {}<br>
<br>
- void BuildConstructorSignature(const CXXConstructorDecl *Ctor,<br>
- CXXCtorType T,<br>
- CanQualType &ResTy,<br>
- SmallVectorImpl<CanQualType> &ArgTys);<br>
-<br>
- void BuildDestructorSignature(const CXXDestructorDecl *Dtor,<br>
- CXXDtorType T,<br>
- CanQualType &ResTy,<br>
- SmallVectorImpl<CanQualType> &ArgTys);<br>
-<br>
- void BuildInstanceFunctionParams(CodeGenFunction &CGF,<br>
- QualType &ResTy,<br>
- FunctionArgList &Params);<br>
-<br>
- void EmitInstanceFunctionProlog(CodeGenFunction &CGF);<br>
+ bool HasThisReturn(GlobalDecl GD) const {<br>
+ return (isa<CXXConstructorDecl>(GD.getDecl()) || (<br>
+ isa<CXXDestructorDecl>(GD.getDecl()) &&<br>
+ GD.getDtorType() != Dtor_Deleting));<br>
+ }<br>
<br>
void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy);<br>
<br>
@@ -191,15 +182,6 @@ public:<br>
QualType ElementType);<br>
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,<br>
CharUnits cookieSize);<br>
-<br>
- /// \brief Returns true if the given instance method is one of the<br>
- /// kinds that the ARM ABI says returns 'this'.<br>
- bool HasThisReturn(GlobalDecl GD) const {<br>
- const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(GD.getDecl());<br>
- if (!MD) return false;<br>
- return ((isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Deleting) ||<br>
- (isa<CXXConstructorDecl>(MD)));<br>
- }<br>
};<br>
}<br>
<br>
@@ -754,22 +736,14 @@ void ItaniumCXXABI::BuildConstructorSign<br>
SmallVectorImpl<CanQualType> &ArgTys) {<br>
ASTContext &Context = getContext();<br>
<br>
- // 'this' is already there.<br>
+ // 'this' parameter is already there, as well as 'this' return if<br>
+ // HasThisReturn(GlobalDecl(Ctor, Type)) is true<br>
<br>
// Check if we need to add a VTT parameter (which has type void **).<br>
if (Type == Ctor_Base && Ctor->getParent()->getNumVBases() != 0)<br>
ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));<br>
}<br>
<br>
-/// The ARM ABI does the same as the Itanium ABI, but returns 'this'.<br>
-void ARMCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,<br>
- CXXCtorType Type,<br>
- CanQualType &ResTy,<br>
- SmallVectorImpl<CanQualType> &ArgTys) {<br>
- ItaniumCXXABI::BuildConstructorSignature(Ctor, Type, ResTy, ArgTys);<br>
- ResTy = ArgTys[0];<br>
-}<br>
-<br>
/// The generic ABI passes 'this', plus a VTT if it's destroying a<br>
/// base subobject.<br>
void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,<br>
@@ -778,25 +752,14 @@ void ItaniumCXXABI::BuildDestructorSigna<br>
SmallVectorImpl<CanQualType> &ArgTys) {<br>
ASTContext &Context = getContext();<br>
<br>
- // 'this' is already there.<br>
+ // 'this' parameter is already there, as well as 'this' return if<br>
+ // HasThisReturn(GlobalDecl(Dtor, Type)) is true<br>
<br>
// Check if we need to add a VTT parameter (which has type void **).<br>
if (Type == Dtor_Base && Dtor->getParent()->getNumVBases() != 0)<br>
ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));<br>
}<br>
<br>
-/// The ARM ABI does the same as the Itanium ABI, but returns 'this'<br>
-/// for non-deleting destructors.<br>
-void ARMCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,<br>
- CXXDtorType Type,<br>
- CanQualType &ResTy,<br>
- SmallVectorImpl<CanQualType> &ArgTys) {<br>
- ItaniumCXXABI::BuildDestructorSignature(Dtor, Type, ResTy, ArgTys);<br>
-<br>
- if (Type != Dtor_Deleting)<br>
- ResTy = ArgTys[0];<br>
-}<br>
-<br>
void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,<br>
QualType &ResTy,<br>
FunctionArgList &Params) {<br>
@@ -820,16 +783,6 @@ void ItaniumCXXABI::BuildInstanceFunctio<br>
}<br>
}<br>
<br>
-void ARMCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,<br>
- QualType &ResTy,<br>
- FunctionArgList &Params) {<br>
- ItaniumCXXABI::BuildInstanceFunctionParams(CGF, ResTy, Params);<br>
-<br>
- // Return 'this' from certain constructors and destructors.<br>
- if (HasThisReturn(CGF.CurGD))<br>
- ResTy = Params[0]->getType();<br>
-}<br>
-<br>
void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {<br>
/// Initialize the 'this' slot.<br>
EmitThisParam(CGF);<br>
@@ -840,21 +793,24 @@ void ItaniumCXXABI::EmitInstanceFunction<br>
= CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getVTTDecl(CGF)),<br>
"vtt");<br>
}<br>
-}<br>
<br>
-void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {<br>
- ItaniumCXXABI::EmitInstanceFunctionProlog(CGF);<br>
-<br>
- /// Initialize the return slot to 'this' at the start of the<br>
- /// function.<br>
+ /// If this is a function that the ABI specifies returns 'this', initialize<br>
+ /// the return slot to 'this' at the start of the function.<br>
+ ///<br>
+ /// Unlike the setting of return types, this is done within the ABI<br>
+ /// implementation instead of by clients of CGCXXABI because:<br>
+ /// 1) getThisValue is currently protected<br>
+ /// 2) in theory, an ABI could implement 'this' returns some other way;<br>
+ /// HasThisReturn only specifies a contract, not the implementation<br>
if (HasThisReturn(CGF.CurGD))<br>
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);<br>
}<br>
<br>
-llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,<br>
+RValue ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,<br>
const CXXConstructorDecl *D,<br>
- CXXCtorType Type, bool ForVirtualBase,<br>
- bool Delegating,<br>
+ CXXCtorType Type,<br>
+ bool ForVirtualBase, bool Delegating,<br>
+ ReturnValueSlot ReturnValue,<br>
llvm::Value *This,<br>
CallExpr::const_arg_iterator ArgBeg,<br>
CallExpr::const_arg_iterator ArgEnd) {<br>
@@ -864,9 +820,8 @@ llvm::Value *ItaniumCXXABI::EmitConstruc<br>
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);<br>
<br>
// FIXME: Provide a source location here.<br>
- CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,<br>
- VTT, VTTTy, ArgBeg, ArgEnd);<br>
- return Callee;<br>
+ return CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValue,<br>
+ This, VTT, VTTTy, ArgBeg, ArgEnd);<br>
}<br>
<br>
RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,<br>
<br>
Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=184205&r1=184204&r2=184205&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=184205&r1=184204&r2=184205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Tue Jun 18 12:00:49 2013<br>
@@ -28,6 +28,8 @@ class MicrosoftCXXABI : public CGCXXABI<br>
public:<br>
MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {}<br>
<br>
+ bool HasThisReturn(GlobalDecl GD) const;<br>
+<br>
bool isReturnTypeIndirect(const CXXRecordDecl *RD) const {<br>
// Structures that are not C++03 PODs are always indirect.<br>
return !RD->isPOD();<br>
@@ -71,13 +73,14 @@ public:<br>
<br>
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);<br>
<br>
- llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,<br>
- const CXXConstructorDecl *D,<br>
- CXXCtorType Type, bool ForVirtualBase,<br>
- bool Delegating,<br>
- llvm::Value *This,<br>
- CallExpr::const_arg_iterator ArgBeg,<br>
- CallExpr::const_arg_iterator ArgEnd);<br>
+ RValue EmitConstructorCall(CodeGenFunction &CGF,<br>
+ const CXXConstructorDecl *D,<br>
+ CXXCtorType Type,<br>
+ bool ForVirtualBase, bool Delegating,<br>
+ ReturnValueSlot ReturnValue,<br>
+ llvm::Value *This,<br>
+ CallExpr::const_arg_iterator ArgBeg,<br>
+ CallExpr::const_arg_iterator ArgEnd);<br>
<br>
RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,<br>
const CXXDestructorDecl *Dtor,<br>
@@ -124,7 +127,6 @@ public:<br>
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,<br>
llvm::Value *allocPtr,<br>
CharUnits cookieSize);<br>
- static bool needThisReturn(GlobalDecl GD);<br>
<br>
private:<br>
llvm::Constant *getZeroInt() {<br>
@@ -299,19 +301,15 @@ MicrosoftCXXABI::GetVirtualBaseClassOffs<br>
return CGF.Builder.CreateNSWAdd(VBPtrOffset, VBPtrToNewBase);<br>
}<br>
<br>
-bool MicrosoftCXXABI::needThisReturn(GlobalDecl GD) {<br>
- const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());<br>
- return isa<CXXConstructorDecl>(MD);<br>
+bool MicrosoftCXXABI::HasThisReturn(GlobalDecl GD) const {<br>
+ return isa<CXXConstructorDecl>(GD.getDecl());<br>
}<br>
<br>
void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,<br>
CXXCtorType Type,<br>
CanQualType &ResTy,<br>
SmallVectorImpl<CanQualType> &ArgTys) {<br>
- // 'this' is already in place<br>
-<br>
- // Ctor returns this ptr<br>
- ResTy = ArgTys[0];<br>
+ // 'this' parameter and 'this' return are already in place<br>
<br>
const CXXRecordDecl *Class = Ctor->getParent();<br>
if (Class->getNumVBases()) {<br>
@@ -346,6 +344,7 @@ void MicrosoftCXXABI::BuildDestructorSig<br>
CanQualType &ResTy,<br>
SmallVectorImpl<CanQualType> &ArgTys) {<br>
// 'this' is already in place<br>
+<br>
// TODO: 'for base' flag<br>
<br>
if (Type == Dtor_Deleting) {<br>
@@ -366,9 +365,6 @@ void MicrosoftCXXABI::BuildInstanceFunct<br>
QualType &ResTy,<br>
FunctionArgList &Params) {<br>
BuildThisParam(CGF, Params);<br>
- if (needThisReturn(CGF.CurGD)) {<br>
- ResTy = Params[0]->getType();<br>
- }<br>
<br>
ASTContext &Context = getContext();<br>
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());<br>
@@ -393,9 +389,17 @@ void MicrosoftCXXABI::BuildInstanceFunct<br>
<br>
void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {<br>
EmitThisParam(CGF);<br>
- if (needThisReturn(CGF.CurGD)) {<br>
+<br>
+ /// If this is a function that the ABI specifies returns 'this', initialize<br>
+ /// the return slot to 'this' at the start of the function.<br>
+ ///<br>
+ /// Unlike the setting of return types, this is done within the ABI<br>
+ /// implementation instead of by clients of CGCXXABI because:<br>
+ /// 1) getThisValue is currently protected<br>
+ /// 2) in theory, an ABI could implement 'this' returns some other way;<br>
+ /// HasThisReturn only specifies a contract, not the implementation<br>
+ if (HasThisReturn(CGF.CurGD))<br>
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);<br>
- }<br>
<br>
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());<br>
if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {<br>
@@ -417,11 +421,13 @@ void MicrosoftCXXABI::EmitInstanceFuncti<br>
}<br>
}<br>
<br>
-llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,<br>
- const CXXConstructorDecl *D,<br>
- CXXCtorType Type, bool ForVirtualBase,<br>
- bool Delegating,<br>
- llvm::Value *This,<br>
+RValue MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,<br>
+ const CXXConstructorDecl *D,<br>
+ CXXCtorType Type,<br>
+ bool ForVirtualBase,<br>
+ bool Delegating,<br>
+ ReturnValueSlot ReturnValue,<br>
+ llvm::Value *This,<br>
CallExpr::const_arg_iterator ArgBeg,<br>
CallExpr::const_arg_iterator ArgEnd) {<br>
assert(Type == Ctor_Complete || Type == Ctor_Base);<br>
@@ -435,10 +441,9 @@ llvm::Value *MicrosoftCXXABI::EmitConstr<br>
}<br>
<br>
// FIXME: Provide a source location here.<br>
- CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,<br>
- ImplicitParam, ImplicitParamTy,<br>
- ArgBeg, ArgEnd);<br>
- return Callee;<br>
+ return CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValue,<br>
+ This, ImplicitParam, ImplicitParamTy,<br>
+ ArgBeg, ArgEnd);<br>
}<br>
<br>
RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/arm.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/arm.cpp?rev=184205&r1=184204&r2=184205&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/arm.cpp?rev=184205&r1=184204&r2=184205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/arm.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/arm.cpp Tue Jun 18 12:00:49 2013<br>
@@ -52,19 +52,19 @@ namespace test1 {<br>
a.bar();<br>
}<br>
<br>
- // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* %this, i32 %i) unnamed_addr<br>
+ // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* returned %this, i32 %i) unnamed_addr<br>
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4<br>
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]<br>
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]<br>
- // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AC2Ei(<br>
- // CHECK: ret [[A]]* [[THIS2]]<br>
+ // CHECK: {{%.*}} = call [[A]]* @_ZN5test11AC2Ei(<br>
+ // CHECK: ret [[A]]* [[THIS1]]<br>
<br>
- // CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr<br>
+ // CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* returned %this) unnamed_addr<br>
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4<br>
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]<br>
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]<br>
- // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AD2Ev(<br>
- // CHECK: ret [[A]]* [[THIS2]]<br>
+ // CHECK: {{%.*}} = call [[A]]* @_ZN5test11AD2Ev(<br>
+ // CHECK: ret [[A]]* [[THIS1]]<br>
}<br>
<br>
// Awkward virtual cases.<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/constructor-destructor-return-this.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/constructor-destructor-return-this.cpp?rev=184205&r1=184204&r2=184205&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/constructor-destructor-return-this.cpp?rev=184205&r1=184204&r2=184205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/constructor-destructor-return-this.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/constructor-destructor-return-this.cpp Tue Jun 18 12:00:49 2013<br>
@@ -1,60 +1,120 @@<br>
-//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck %s<br>
+//RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-unknown-linux | FileCheck --check-prefix=CHECKGEN %s<br>
+//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck --check-prefix=CHECKARM %s<br>
+//RUN: %clang_cc1 %s -emit-llvm -o - -DPR12784_WORKAROUND -triple=x86_64-pc-win32 -cxx-abi microsoft | FileCheck --check-prefix=CHECKMS %s<br>
<br>
-// For constructors/desctructors that return 'this', if there exists a callsite<br>
-// that returns 'this' and is immediately before the return instruction, make<br>
-// sure we are using the return value from the callsite.<br>
-// rdar://12818789<br>
-<br>
-// CHECK: define linkonce_odr [[A:%.*]] @_ZN11ObjectCacheC1Ev([[A]] %this) unnamed_addr<br>
-// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN11ObjectCacheC2Ev(<br>
-// CHECK-NEXT: ret [[A]] [[THIS1]]<br>
-<br>
-// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheEC1EPS0_MS0_FvPS1_E([[A]] %this<br>
-// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheEC2EPS0_MS0_FvPS1_E(<br>
-// CHECK-NEXT: ret [[A]] [[THIS1]]<br>
-<br>
-// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED1Ev([[A]] %this) unnamed_addr<br>
-// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheED2Ev(<br>
-// CHECK-NEXT: ret [[A]] [[THIS1]]<br>
-<br>
-// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED2Ev([[A]] %this) unnamed_addr<br>
-// CHECK: [[THIS1:%.*]] = call [[B:%.*]] @_ZN9TimerBaseD2Ev(<br>
-// CHECK-NEXT: [[THIS2:%.*]] = bitcast [[B]] [[THIS1]] to [[A]]<br>
-// CHECK-NEXT: ret [[A]] [[THIS2]]<br>
+// FIXME: Add checks to ensure that Microsoft destructors do not return 'this'<br>
+// once PR12784 is resolved<br>
<br>
-class TimerBase {<br>
+// Make sure we attach the 'returned' attribute to the 'this' parameter of<br>
+// constructors and destructors which return this (and only these cases)<br>
+<br>
+class A {<br>
public:<br>
- TimerBase();<br>
- virtual ~TimerBase();<br>
+ A();<br>
+ ~A();<br>
+<br>
+private:<br>
+ int x_;<br>
};<br>
<br>
-template <typename TimerFiredClass> class Timer : public TimerBase {<br>
+class B : public A {<br>
public:<br>
- typedef void (TimerFiredClass::*TimerFiredFunction)(Timer*);<br>
-<br>
- Timer(TimerFiredClass* o, TimerFiredFunction f)<br>
- : m_object(o), m_function(f) { }<br>
+ B(int *i);<br>
+ ~B();<br>
<br>
private:<br>
- virtual void fired() { (m_object->*m_function)(this); }<br>
+ int *i_;<br>
+};<br>
<br>
- TimerFiredClass* m_object;<br>
- TimerFiredFunction m_function;<br>
+B::B(int *i) : i_(i) { }<br>
+#ifndef PR12784_WORKAROUND<br>
+B::~B() { }<br>
+#endif<br>
+<br>
+// CHECKGEN: define void @_ZN1BC1EPi(%class.B* %this, i32* %i)<br>
+// CHECKGEN: define void @_ZN1BC2EPi(%class.B* %this, i32* %i)<br>
+// CHECKGEN: define void @_ZN1BD1Ev(%class.B* %this)<br>
+// CHECKGEN: define void @_ZN1BD2Ev(%class.B* %this)<br>
+<br>
+// CHECKARM: define %class.B* @_ZN1BC1EPi(%class.B* returned %this, i32* %i)<br>
+// CHECKARM: define %class.B* @_ZN1BC2EPi(%class.B* returned %this, i32* %i)<br>
+// CHECKARM: define %class.B* @_ZN1BD1Ev(%class.B* returned %this)<br>
+// CHECKARM: define %class.B* @_ZN1BD2Ev(%class.B* returned %this)<br>
+<br>
+// CHECKMS: define %class.B* @"\01??0B@@QEAA@PEAH@Z"(%class.B* returned %this, i32* %i)<br>
+<br>
+class C : public A, public B {<br>
+public:<br>
+ C(int *i, char *c);<br>
+ virtual ~C();<br>
+private:<br>
+ char *c_;<br>
};<br>
<br>
-class ObjectCache {<br>
+C::C(int *i, char *c) : B(i), c_(c) { }<br>
+#ifndef PR12784_WORKAROUND<br>
+C::~C() { }<br>
+#endif<br>
+<br>
+// CHECKGEN: define void @_ZN1CC1EPiPc(%class.C* %this, i32* %i, i8* %c)<br>
+// CHECKGEN: define void @_ZN1CC2EPiPc(%class.C* %this, i32* %i, i8* %c)<br>
+// CHECKGEN: define void @_ZN1CD0Ev(%class.C* %this)<br>
+// CHECKGEN: define void @_ZN1CD1Ev(%class.C* %this)<br>
+// CHECKGEN: define void @_ZN1CD2Ev(%class.C* %this)<br>
+<br>
+// CHECKARM: define %class.C* @_ZN1CC1EPiPc(%class.C* returned %this, i32* %i, i8* %c)<br>
+// CHECKARM: define %class.C* @_ZN1CC2EPiPc(%class.C* returned %this, i32* %i, i8* %c)<br>
+// CHECKARM: define void @_ZN1CD0Ev(%class.C* %this)<br>
+// CHECKARM: define %class.C* @_ZN1CD1Ev(%class.C* returned %this)<br>
+// CHECKARM: define %class.C* @_ZN1CD2Ev(%class.C* returned %this)<br>
+<br>
+// CHECKMS: define %class.C* @"\01??0C@@QEAA@PEAHPEAD@Z"(%class.C* returned %this, i32* %i, i8* %c)<br>
+<br>
+class D : public virtual A {<br>
public:<br>
- explicit ObjectCache();<br>
- ~ObjectCache();<br>
+ D();<br>
+ ~D();<br>
+};<br>
<br>
-private:<br>
- Timer<ObjectCache> m_notificationPostTimer;<br>
+#ifndef PR12784_WORKAROUND<br>
+D::D() { }<br>
+D::~D() { }<br>
+#endif<br>
+<br>
+// CHECKGEN: define void @_ZN1DC1Ev(%class.D* %this)<br>
+// CHECKGEN: define void @_ZN1DC2Ev(%class.D* %this, i8** %vtt)<br>
+// CHECKGEN: define void @_ZN1DD1Ev(%class.D* %this)<br>
+// CHECKGEN: define void @_ZN1DD2Ev(%class.D* %this, i8** %vtt)<br>
+<br>
+// CHECKARM: define %class.D* @_ZN1DC1Ev(%class.D* returned %this)<br>
+// CHECKARM: define %class.D* @_ZN1DC2Ev(%class.D* returned %this, i8** %vtt)<br>
+// CHECKARM: define %class.D* @_ZN1DD1Ev(%class.D* returned %this)<br>
+// CHECKARM: define %class.D* @_ZN1DD2Ev(%class.D* returned %this, i8** %vtt)<br>
+<br>
+class E {<br>
+public:<br>
+ E();<br>
+ virtual ~E();<br>
};<br>
<br>
-inline ObjectCache::ObjectCache() : m_notificationPostTimer(this, 0) { }<br>
-inline ObjectCache::~ObjectCache() { }<br>
+E* gete();<br>
<br>
-ObjectCache *test() {<br>
- ObjectCache *dd = new ObjectCache();<br>
- return dd;<br>
+void test_destructor() {<br>
+ E* e1 = new E();<br>
+ E* e2 = gete();<br>
+ e1->~E();<br>
+ e2->~E();<br>
}<br>
+<br>
+// CHECKARM: define void @_Z15test_destructorv()<br>
+<br>
+// CHECKARM: {{%.*}} = call %class.E* @_ZN1EC1Ev(%class.E*<br>
+<br>
+// Verify that virtual calls to destructors are not marked with a 'returned'<br>
+// this parameter at the call site...<br>
+// CHECKARM: [[VFN:%.*]] = getelementptr inbounds %class.E* (%class.E*)**<br>
+// CHECKARM: [[THUNK:%.*]] = load %class.E* (%class.E*)** [[VFN]]<br>
+// CHECKARM: call %class.E* [[THUNK]](%class.E*<br>
+<br>
+// ...but static calls create declarations with 'returned' this<br>
+// CHECKARM: declare %class.E* @_ZN1EC1Ev(%class.E* returned)<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/copy-constructor-elim-2.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/copy-constructor-elim-2.cpp?rev=184205&r1=184204&r2=184205&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/copy-constructor-elim-2.cpp?rev=184205&r1=184204&r2=184205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/copy-constructor-elim-2.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/copy-constructor-elim-2.cpp Tue Jun 18 12:00:49 2013<br>
@@ -21,7 +21,7 @@ namespace no_elide_base {<br>
Derived(const Other &O);<br>
};<br>
<br>
- // CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* %this, %"struct.no_elide_base::Other"* %O) unnamed_addr<br>
+ // CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* returned %this, %"struct.no_elide_base::Other"* %O) unnamed_addr<br>
Derived::Derived(const Other &O)<br>
// CHECK: call {{.*}} @_ZNK13no_elide_base5OthercvNS_4BaseEEv<br>
// CHECK: call {{.*}} @_ZN13no_elide_base4BaseC2ERKS0_<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp?rev=184205&r1=184204&r2=184205&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp?rev=184205&r1=184204&r2=184205&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp Tue Jun 18 12:00:49 2013<br>
@@ -15,7 +15,7 @@ class A {<br>
void no_constructor_destructor_infinite_recursion() {<br>
A a;<br>
<br>
-// CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* %this)<br>
+// CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* returned %this)<br>
// CHECK: [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca %"class.basic::A"*, align 4<br>
// CHECK-NEXT: store %"class.basic::A"* %this, %"class.basic::A"** [[THIS_ADDR]], align 4<br>
// CHECK-NEXT: [[T1:%[.0-9A-Z_a-z]+]] = load %"class.basic::A"** [[THIS_ADDR]]<br>
@@ -34,7 +34,7 @@ struct B {<br>
<br>
// Tests that we can define constructors outside the class (PR12784).<br>
B::B() {<br>
- // CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* %this)<br>
+ // CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* returned %this)<br>
// CHECK: ret<br>
}<br>
<br>
@@ -136,7 +136,7 @@ struct B : A {<br>
};<br>
<br>
B::B() {<br>
- // CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* %this)<br>
+ // CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* returned %this)<br>
// CHECK: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})<br>
// CHECK: ret<br>
}<br>
@@ -146,7 +146,7 @@ struct C : virtual A {<br>
};<br>
<br>
C::C() {<br>
- // CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %this, i32 %is_most_derived)<br>
+ // CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* returned %this, i32 %is_most_derived)<br>
// TODO: make sure this works in the Release build too;<br>
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4<br>
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]<br>
@@ -175,7 +175,7 @@ struct D : C {<br>
};<br>
<br>
D::D() {<br>
- // CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* %this, i32 %is_most_derived) unnamed_addr<br>
+ // CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* returned %this, i32 %is_most_derived) unnamed_addr<br>
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4<br>
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]<br>
// CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0<br>
@@ -196,7 +196,7 @@ struct E : virtual C {<br>
};<br>
<br>
E::E() {<br>
- // CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* %this, i32 %is_most_derived) unnamed_addr<br>
+ // CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* returned %this, i32 %is_most_derived) unnamed_addr<br>
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4<br>
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]<br>
// CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div></div>