diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/CodeGen/CGCXXABI.h | 4 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 65 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 5 | ||||
-rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.cpp | 20 |
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); } |