CodeGen: Have 'this'-returning constructors and destructors to take advantage of the new backend 'returned' attribute.
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).
This patch also reverts a prior front-end only partial implementation of these optimizations, since it's no longer required.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184205 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index f64a633..899e5e7 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -97,8 +97,12 @@
return *MangleCtx;
}
- /// Returns true if the given instance method is one of the
- /// kinds that the ABI says returns 'this'.
+ /// Returns true if the given constructor or destructor is one of the
+ /// kinds that the ABI says returns 'this' (only applies when called
+ /// 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; }
/// Returns true if the given record type should be returned indirectly.
@@ -214,10 +218,10 @@
const CXXRecordDecl *BaseClassDecl) = 0;
/// Build the signature of the given constructor variant by adding
- /// any required parameters. For convenience, ResTy has been
- /// initialized to 'void', and ArgTys has been initialized with the
- /// type of 'this' (although this may be changed by the ABI) and
- /// will have the formal parameters added to it afterwards.
+ /// any required parameters. For convenience, ArgTys has been initialized
+ /// with the type of 'this' and ResTy has been initialized with the type of
+ /// 'this' if HasThisReturn(GlobalDecl(Ctor, T)) is true or 'void' otherwise
+ /// (although both may be changed by the ABI).
///
/// If there are ever any ABIs where the implicit parameters are
/// intermixed with the formal parameters, we can address those
@@ -230,9 +234,10 @@
virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF);
/// Build the signature of the given destructor variant by adding
- /// any required parameters. For convenience, ResTy has been
- /// initialized to 'void' and ArgTys has been initialized with the
- /// type of 'this' (although this may be changed by the ABI).
+ /// any required parameters. For convenience, ArgTys has been initialized
+ /// with the type of 'this' and ResTy has been initialized with the type of
+ /// 'this' if HasThisReturn(GlobalDecl(Dtor, T)) is true or 'void' otherwise
+ /// (although both may be changed by the ABI).
virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
CXXDtorType T,
CanQualType &ResTy,
@@ -243,7 +248,8 @@
/// possibly some extra data for constructors and destructors.
///
/// ABIs may also choose to override the return type, which has been
- /// initialized with the formal return type of the function.
+ /// initialized with the type of 'this' if HasThisReturn(CGF.CurGD) is true or
+ /// the formal return type of the function otherwise.
virtual void BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
FunctionArgList &Params) = 0;
@@ -252,13 +258,14 @@
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
/// Emit the constructor call. Return the function that is called.
- virtual llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
- const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating,
- llvm::Value *This,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd) = 0;
+ virtual RValue EmitConstructorCall(CodeGenFunction &CGF,
+ const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ bool ForVirtualBase, bool Delegating,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) = 0;
/// Emit the ABI-specific virtual destructor call.
virtual RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 8044639..f74ae39 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -200,7 +200,10 @@
CXXCtorType ctorKind) {
SmallVector<CanQualType, 16> argTypes;
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);
@@ -225,7 +228,10 @@
CXXDtorType dtorKind) {
SmallVector<CanQualType, 2> argTypes;
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);
@@ -1633,18 +1639,6 @@
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,
bool EmitRetDbgLoc) {
// Functions with no result always return void.
@@ -1741,19 +1735,6 @@
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();
if (!RetDbgLoc.isUnknown())
Ret->setDebugLoc(RetDbgLoc);
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 9d08d1c..88f5cf9 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -1661,11 +1661,9 @@
}
// Non-trivial constructors are handled in an ABI-specific manner.
- llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type,
- ForVirtualBase, Delegating, This, ArgBeg, ArgEnd);
- if (CGM.getCXXABI().HasThisReturn(CurGD) &&
- CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type)))
- CalleeWithThisReturn = Callee;
+ CGM.getCXXABI().EmitConstructorCall(*this, D, Type,
+ ForVirtualBase, Delegating,
+ ReturnValueSlot(), This, ArgBeg, ArgEnd);
}
void
@@ -1757,9 +1755,6 @@
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
Callee, ReturnValueSlot(), DelegateArgs, Ctor);
- if (CGM.getCXXABI().HasThisReturn(CurGD) &&
- CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType)))
- CalleeWithThisReturn = Callee;
}
namespace {
@@ -1826,9 +1821,6 @@
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
VTT, getContext().getPointerType(getContext().VoidPtrTy),
0, 0);
- if (CGM.getCXXABI().HasThisReturn(CurGD) &&
- CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type)))
- CalleeWithThisReturn = Callee;
}
namespace {
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index b1072b4..d116877 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -287,8 +287,9 @@
GlobalDecl GD, const ThunkInfo &Thunk) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- QualType ResultType = FPT->getResultType();
QualType ThisType = MD->getThisType(getContext());
+ QualType ResultType =
+ CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getResultType();
FunctionArgList FunctionArgs;
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 297fc65..e8469e6 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -42,8 +42,7 @@
AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1),
FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
- DebugInfo(0), DisableDebugInfo(false), CalleeWithThisReturn(0),
- DidCallStackSave(false),
+ DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
NumReturnExprs(0), NumSimpleReturnExprs(0),
CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0),
@@ -662,8 +661,12 @@
QualType ResTy = FD->getResultType();
CurGD = GD;
- if (isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isInstance())
+ const CXXMethodDecl *MD;
+ if ((MD = dyn_cast<CXXMethodDecl>(FD)) && MD->isInstance()) {
+ if (CGM.getCXXABI().HasThisReturn(GD))
+ ResTy = MD->getThisType(getContext());
CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args);
+ }
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i)
Args.push_back(FD->getParamDecl(i));
@@ -672,10 +675,6 @@
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
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.
StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
@@ -727,9 +726,6 @@
// Emit the standard function epilogue.
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
// a quick pass now to see if we can.
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 508e6a4..9071e07 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -798,10 +798,6 @@
CGDebugInfo *DebugInfo;
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
/// calling llvm.stacksave for multiple VLAs in the same scope.
bool DidCallStackSave;
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 824d2a0..d76fee5 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -717,6 +717,14 @@
if (!IsIncompleteFunction)
SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F);
+ if (getCXXABI().HasThisReturn(GD)) {
+ llvm::Type *RetTy = F->getReturnType();
+ assert(!F->arg_empty() &&
+ F->arg_begin()->getType()->canLosslesslyBitCastTo(RetTy) &&
+ "unexpected this return");
+ F->addAttribute(1, llvm::Attribute::Returned);
+ }
+
// Only a few attributes are set on declarations; these may later be
// overridden by a definition.
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 6cf95b5..7228400 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -119,13 +119,14 @@
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
- llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
- const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating,
- llvm::Value *This,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd);
+ RValue EmitConstructorCall(CodeGenFunction &CGF,
+ const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ bool ForVirtualBase, bool Delegating,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd);
RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor,
@@ -165,21 +166,11 @@
public:
ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {}
- void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
- CXXCtorType T,
- CanQualType &ResTy,
- 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);
+ bool HasThisReturn(GlobalDecl GD) const {
+ return (isa<CXXConstructorDecl>(GD.getDecl()) || (
+ isa<CXXDestructorDecl>(GD.getDecl()) &&
+ GD.getDtorType() != Dtor_Deleting));
+ }
void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy);
@@ -191,15 +182,6 @@
QualType ElementType);
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
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)));
- }
};
}
@@ -754,22 +736,14 @@
SmallVectorImpl<CanQualType> &ArgTys) {
ASTContext &Context = getContext();
- // 'this' is already there.
+ // 'this' parameter is already there, as well as 'this' return if
+ // HasThisReturn(GlobalDecl(Ctor, Type)) is true
// Check if we need to add a VTT parameter (which has type void **).
if (Type == Ctor_Base && Ctor->getParent()->getNumVBases() != 0)
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
/// base subobject.
void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
@@ -778,25 +752,14 @@
SmallVectorImpl<CanQualType> &ArgTys) {
ASTContext &Context = getContext();
- // 'this' is already there.
+ // 'this' parameter is already there, as well as 'this' return if
+ // HasThisReturn(GlobalDecl(Dtor, Type)) is true
// Check if we need to add a VTT parameter (which has type void **).
if (Type == Dtor_Base && Dtor->getParent()->getNumVBases() != 0)
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,
QualType &ResTy,
FunctionArgList &Params) {
@@ -820,16 +783,6 @@
}
}
-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) {
/// Initialize the 'this' slot.
EmitThisParam(CGF);
@@ -840,21 +793,24 @@
= CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getVTTDecl(CGF)),
"vtt");
}
-}
-void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
- ItaniumCXXABI::EmitInstanceFunctionProlog(CGF);
-
- /// Initialize the return slot to 'this' at the start of the
- /// function.
+ /// 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);
}
-llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
+RValue ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating,
+ CXXCtorType Type,
+ bool ForVirtualBase, bool Delegating,
+ ReturnValueSlot ReturnValue,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
@@ -864,9 +820,8 @@
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
// FIXME: Provide a source location here.
- CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
- VTT, VTTTy, ArgBeg, ArgEnd);
- return Callee;
+ return CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValue,
+ This, VTT, VTTTy, ArgBeg, ArgEnd);
}
RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 1bb2c55..e6eca28 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -28,6 +28,8 @@
public:
MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {}
+ bool HasThisReturn(GlobalDecl GD) const;
+
bool isReturnTypeIndirect(const CXXRecordDecl *RD) const {
// Structures that are not C++03 PODs are always indirect.
return !RD->isPOD();
@@ -71,13 +73,14 @@
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
- llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
- const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating,
- llvm::Value *This,
- CallExpr::const_arg_iterator ArgBeg,
- CallExpr::const_arg_iterator ArgEnd);
+ RValue EmitConstructorCall(CodeGenFunction &CGF,
+ const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ bool ForVirtualBase, bool Delegating,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd);
RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor,
@@ -124,7 +127,6 @@
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
llvm::Value *allocPtr,
CharUnits cookieSize);
- static bool needThisReturn(GlobalDecl GD);
private:
llvm::Constant *getZeroInt() {
@@ -299,19 +301,15 @@
return CGF.Builder.CreateNSWAdd(VBPtrOffset, VBPtrToNewBase);
}
-bool MicrosoftCXXABI::needThisReturn(GlobalDecl GD) {
- const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
- return isa<CXXConstructorDecl>(MD);
+bool MicrosoftCXXABI::HasThisReturn(GlobalDecl GD) const {
+ return isa<CXXConstructorDecl>(GD.getDecl());
}
void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CXXCtorType Type,
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) {
- // 'this' is already in place
-
- // Ctor returns this ptr
- ResTy = ArgTys[0];
+ // 'this' parameter and 'this' return are already in place
const CXXRecordDecl *Class = Ctor->getParent();
if (Class->getNumVBases()) {
@@ -346,6 +344,7 @@
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) {
// 'this' is already in place
+
// TODO: 'for base' flag
if (Type == Dtor_Deleting) {
@@ -366,9 +365,6 @@
QualType &ResTy,
FunctionArgList &Params) {
BuildThisParam(CGF, Params);
- if (needThisReturn(CGF.CurGD)) {
- ResTy = Params[0]->getType();
- }
ASTContext &Context = getContext();
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
@@ -393,9 +389,17 @@
void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &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);
- }
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
@@ -417,11 +421,13 @@
}
}
-llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
- const CXXConstructorDecl *D,
- CXXCtorType Type, bool ForVirtualBase,
- bool Delegating,
- llvm::Value *This,
+RValue MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
+ const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ bool ForVirtualBase,
+ bool Delegating,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
assert(Type == Ctor_Complete || Type == Ctor_Base);
@@ -435,10 +441,9 @@
}
// FIXME: Provide a source location here.
- CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
- ImplicitParam, ImplicitParamTy,
- ArgBeg, ArgEnd);
- return Callee;
+ return CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValue,
+ This, ImplicitParam, ImplicitParamTy,
+ ArgBeg, ArgEnd);
}
RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,