summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CodeGen/CGCXXABI.h4
-rw-r--r--clang/lib/CodeGen/CGCall.cpp65
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp5
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp2
-rw-r--r--clang/lib/CodeGen/TargetInfo.cpp20
5 files changed, 76 insertions, 20 deletions
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h
index fb52838e919..868c1f90930 100644
--- a/clang/lib/CodeGen/CGCXXABI.h
+++ b/clang/lib/CodeGen/CGCXXABI.h
@@ -114,6 +114,10 @@ public:
/// Returns how an argument of the given record type should be passed.
virtual RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const = 0;
+ /// Returns true if the implicit 'sret' parameter comes after the implicit
+ /// 'this' parameter of C++ instance methods.
+ virtual bool isSRetParameterAfterThis() const { return false; }
+
/// Find the LLVM type used to represent the given member pointer
/// type.
virtual llvm::Type *
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 56004f364f1..cf764d635b7 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -940,6 +940,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
bool Inserted = FunctionsBeingProcessed.insert(&FI); (void)Inserted;
assert(Inserted && "Recursively being processed?");
+ bool SwapThisWithSRet = false;
SmallVector<llvm::Type*, 8> argTypes;
llvm::Type *resultType = 0;
@@ -973,6 +974,8 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
llvm::Type *ty = ConvertType(ret);
unsigned addressSpace = Context.getTargetAddressSpace(ret);
argTypes.push_back(llvm::PointerType::get(ty, addressSpace));
+
+ SwapThisWithSRet = retAI.isSRetAfterThis();
break;
}
@@ -1035,6 +1038,9 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
if (llvm::StructType *ArgStruct = FI.getArgStruct())
argTypes.push_back(ArgStruct->getPointerTo());
+ if (SwapThisWithSRet)
+ std::swap(argTypes[0], argTypes[1]);
+
bool Erased = FunctionsBeingProcessed.erase(&FI); (void)Erased;
assert(Erased && "Not in set?");
@@ -1149,6 +1155,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
QualType RetTy = FI.getReturnType();
unsigned Index = 1;
+ bool SwapThisWithSRet = false;
const ABIArgInfo &RetAI = FI.getReturnInfo();
switch (RetAI.getKind()) {
case ABIArgInfo::Extend:
@@ -1176,10 +1183,12 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
SRETAttrs.addAttribute(llvm::Attribute::StructRet);
if (RetAI.getInReg())
SRETAttrs.addAttribute(llvm::Attribute::InReg);
- PAL.push_back(llvm::
- AttributeSet::get(getLLVMContext(), Index, SRETAttrs));
+ SwapThisWithSRet = RetAI.isSRetAfterThis();
+ PAL.push_back(llvm::AttributeSet::get(
+ getLLVMContext(), SwapThisWithSRet ? 2 : Index, SRETAttrs));
- ++Index;
+ if (!SwapThisWithSRet)
+ ++Index;
// sret disables readnone and readonly
FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
.removeAttribute(llvm::Attribute::ReadNone);
@@ -1201,6 +1210,11 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const ABIArgInfo &AI = I.info;
llvm::AttrBuilder Attrs;
+ // Skip over the sret parameter when it comes second. We already handled it
+ // above.
+ if (Index == 2 && SwapThisWithSRet)
+ ++Index;
+
if (AI.getPaddingType()) {
if (AI.getPaddingInReg())
PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index,
@@ -1344,13 +1358,20 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
assert(ArgStruct->getType() == FI.getArgStruct()->getPointerTo());
}
- // Name the struct return argument.
- if (CGM.ReturnTypeUsesSRet(FI)) {
+ // Name the struct return parameter, which can come first or second.
+ const ABIArgInfo &RetAI = FI.getReturnInfo();
+ bool SwapThisWithSRet = false;
+ if (RetAI.isIndirect()) {
+ SwapThisWithSRet = RetAI.isSRetAfterThis();
+ if (SwapThisWithSRet)
+ ++AI;
AI->setName("agg.result");
- AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
- AI->getArgNo() + 1,
+ AI->addAttr(llvm::AttributeSet::get(getLLVMContext(), AI->getArgNo() + 1,
llvm::Attribute::NoAlias));
- ++AI;
+ if (SwapThisWithSRet)
+ --AI; // Go back to the beginning for 'this'.
+ else
+ ++AI; // Skip the sret parameter.
}
// Track if we received the parameter as a pointer (indirect, byval, or
@@ -1580,6 +1601,9 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
}
++AI;
+
+ if (ArgNo == 1 && SwapThisWithSRet)
+ ++AI; // Skip the sret parameter.
}
if (FI.usesInAlloca())
@@ -1822,13 +1846,15 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
break;
case ABIArgInfo::Indirect: {
+ auto AI = CurFn->arg_begin();
+ if (RetAI.isSRetAfterThis())
+ ++AI;
switch (getEvaluationKind(RetTy)) {
case TEK_Complex: {
ComplexPairTy RT =
EmitLoadOfComplex(MakeNaturalAlignAddrLValue(ReturnValue, RetTy),
EndLoc);
- EmitStoreOfComplex(RT,
- MakeNaturalAlignAddrLValue(CurFn->arg_begin(), RetTy),
+ EmitStoreOfComplex(RT, MakeNaturalAlignAddrLValue(AI, RetTy),
/*isInit*/ true);
break;
}
@@ -1837,7 +1863,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
break;
case TEK_Scalar:
EmitStoreOfScalar(Builder.CreateLoad(ReturnValue),
- MakeNaturalAlignAddrLValue(CurFn->arg_begin(), RetTy),
+ MakeNaturalAlignAddrLValue(AI, RetTy),
/*isInit*/ true);
break;
}
@@ -2600,13 +2626,19 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// If the call returns a temporary with struct return, create a temporary
// alloca to hold the result, unless one is given to us.
llvm::Value *SRetPtr = 0;
- if (CGM.ReturnTypeUsesSRet(CallInfo) || RetAI.isInAlloca()) {
+ bool SwapThisWithSRet = false;
+ if (RetAI.isIndirect() || RetAI.isInAlloca()) {
SRetPtr = ReturnValue.getValue();
if (!SRetPtr)
SRetPtr = CreateMemTemp(RetTy);
- if (CGM.ReturnTypeUsesSRet(CallInfo)) {
+ if (RetAI.isIndirect()) {
Args.push_back(SRetPtr);
+ SwapThisWithSRet = RetAI.isSRetAfterThis();
+ if (SwapThisWithSRet)
+ IRArgNo = 1;
checkArgMatches(SRetPtr, IRArgNo, IRFuncTy);
+ if (SwapThisWithSRet)
+ IRArgNo = 0;
} else {
llvm::Value *Addr =
Builder.CreateStructGEP(ArgMemory, RetAI.getInAllocaFieldIndex());
@@ -2622,6 +2654,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
const ABIArgInfo &ArgInfo = info_it->info;
RValue RV = I->RV;
+ // Skip 'sret' if it came second.
+ if (IRArgNo == 1 && SwapThisWithSRet)
+ ++IRArgNo;
+
CharUnits TypeAlign = getContext().getTypeAlignInChars(I->Ty);
// Insert a padding argument to ensure proper alignment.
@@ -2811,6 +2847,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
}
+ if (SwapThisWithSRet)
+ std::swap(Args[0], Args[1]);
+
if (ArgMemory) {
llvm::Value *Arg = ArgMemory;
llvm::Type *LastParamTy =
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index f3ea8ebe9e5..178cf9f2b30 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -622,7 +622,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
!hasScalarEvaluationKind(CurFnInfo->getReturnType())) {
// Indirect aggregate return; emit returned value directly into sret slot.
// This reduces code size, and affects correctness in C++.
- ReturnValue = CurFn->arg_begin();
+ auto AI = CurFn->arg_begin();
+ if (CurFnInfo->getReturnInfo().isSRetAfterThis())
+ ++AI;
+ ReturnValue = AI;
} else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::InAlloca &&
!hasScalarEvaluationKind(CurFnInfo->getReturnType())) {
// Load the sret pointer from the argument struct and return into that.
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index f22b96a6a07..bd56b732ec4 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -46,6 +46,8 @@ public:
RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override;
+ bool isSRetParameterAfterThis() const override { return true; }
+
StringRef GetPureVirtualCallName() override { return "_purecall"; }
// No known support for deleted functions in MSVC yet, so this choice is
// arbitrary.
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index 64f9e7b544c..6f0df6bda11 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -992,13 +992,13 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
FI.getReturnInfo() =
classifyReturnType(FI.getReturnType(), State, FI.isInstanceMethod());
- // On win32, use the x86_cdeclmethodcc convention for cdecl methods that use
- // sret. This convention swaps the order of the first two parameters behind
- // the scenes to match MSVC.
+ // On win32, swap the order of the first two parameters for instance methods
+ // which are sret behind the scenes to match MSVC.
if (IsWin32StructABI && FI.isInstanceMethod() &&
- FI.getCallingConvention() == llvm::CallingConv::C &&
- FI.getReturnInfo().isIndirect())
- FI.setEffectiveCallingConvention(llvm::CallingConv::X86_CDeclMethod);
+ FI.getReturnInfo().isIndirect()) {
+ assert(FI.arg_size() >= 1 && "instance method should have this");
+ FI.getReturnInfo().setSRetAfterThis(true);
+ }
bool UsedInAlloca = false;
for (auto &I : FI.arguments()) {
@@ -2768,6 +2768,14 @@ void WinX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
QualType RetTy = FI.getReturnType();
FI.getReturnInfo() = classify(RetTy, true);
+ // On win64, swap the order of the first two parameters for instance methods
+ // which are sret behind the scenes to match MSVC.
+ if (FI.getReturnInfo().isIndirect() && FI.isInstanceMethod() &&
+ getCXXABI().isSRetParameterAfterThis()) {
+ assert(FI.arg_size() >= 1 && "instance method should have this");
+ FI.getReturnInfo().setSRetAfterThis(true);
+ }
+
for (auto &I : FI.arguments())
I.info = classify(I.type, false);
}
OpenPOWER on IntegriCloud