diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h --- a/clang/include/clang/CodeGen/CGFunctionInfo.h +++ b/clang/include/clang/CodeGen/CGFunctionInfo.h @@ -567,6 +567,10 @@ /// Whether this is a chain call. unsigned ChainCall : 1; + /// Whether this function is called by forwarding arguments. + /// This doesn't support inalloca or varargs. + unsigned DelegateCall: 1; + /// Whether this function is a CMSE nonsecure call unsigned CmseNSCall : 1; @@ -619,6 +623,7 @@ static CGFunctionInfo *create(unsigned llvmCC, bool instanceMethod, bool chainCall, + bool delegateCall, const FunctionType::ExtInfo &extInfo, ArrayRef paramInfos, CanQualType resultType, @@ -663,6 +668,8 @@ bool isChainCall() const { return ChainCall; } + bool isDelegateCall() const { return DelegateCall; } + bool isCmseNSCall() const { return CmseNSCall; } bool isNoReturn() const { return NoReturn; } diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h --- a/clang/lib/CodeGen/CGCall.h +++ b/clang/lib/CodeGen/CGCall.h @@ -377,6 +377,34 @@ bool isExternallyDestructed() const { return IsExternallyDestructed; } }; +enum class FnInfoOpts { + None = 0, + IsInstanceMethod = 1 << 0, + IsChainCall = 1 << 1, + IsDelegateCall = 1 << 2, +}; + +inline FnInfoOpts operator|(FnInfoOpts A, FnInfoOpts B) { + return static_cast(static_cast>(A) | + static_cast>(B)); +} + +inline FnInfoOpts operator&(FnInfoOpts A, FnInfoOpts B) { + return static_cast(static_cast>(A) & + static_cast>(B)); +} + +inline FnInfoOpts operator|=(FnInfoOpts A, FnInfoOpts B) { + A = A | B; + return A; +} + +inline FnInfoOpts operator&=(FnInfoOpts A, FnInfoOpts B) { + A = A & B; + return A; +} + + } // end namespace CodeGen } // end namespace clang diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -111,9 +111,8 @@ // When translating an unprototyped function type, always use a // variadic type. return arrangeLLVMFunctionInfo(FTNP->getReturnType().getUnqualifiedType(), - /*instanceMethod=*/false, - /*chainCall=*/false, None, - FTNP->getExtInfo(), {}, RequiredArgs(0)); + FnInfoOpts::None, None, FTNP->getExtInfo(), {}, + RequiredArgs(0)); } static void addExtParameterInfosForCall( @@ -188,10 +187,10 @@ appendParameterTypes(CGT, prefix, paramInfos, FTP); CanQualType resultType = FTP->getReturnType().getUnqualifiedType(); - return CGT.arrangeLLVMFunctionInfo(resultType, instanceMethod, - /*chainCall=*/false, prefix, - FTP->getExtInfo(), paramInfos, - Required); + FnInfoOpts opts = instanceMethod ? + FnInfoOpts::IsInstanceMethod : FnInfoOpts::None; + return CGT.arrangeLLVMFunctionInfo(resultType, opts, prefix, FTP->getExtInfo(), + paramInfos, Required); } /// Arrange the argument and result information for a value of the @@ -270,7 +269,7 @@ argTypes.push_back(DeriveThisType(RD, MD)); return ::arrangeLLVMFunctionInfo( - *this, true, argTypes, + *this, /*instanceMethod=*/true, argTypes, FTP->getCanonicalTypeUnqualified().getAs()); } @@ -360,9 +359,8 @@ : TheCXXABI.hasMostDerivedReturn(GD) ? CGM.getContext().VoidPtrTy : Context.VoidTy; - return arrangeLLVMFunctionInfo(resultType, /*instanceMethod=*/true, - /*chainCall=*/false, argTypes, extInfo, - paramInfos, required); + return arrangeLLVMFunctionInfo(resultType, FnInfoOpts::IsInstanceMethod, argTypes, + extInfo, paramInfos, required); } static SmallVector @@ -436,9 +434,9 @@ addExtParameterInfosForCall(ParamInfos, FPT.getTypePtr(), TotalPrefixArgs, ArgTypes.size()); } - return arrangeLLVMFunctionInfo(ResultType, /*instanceMethod=*/true, - /*chainCall=*/false, ArgTypes, Info, - ParamInfos, Required); + + return arrangeLLVMFunctionInfo(ResultType, FnInfoOpts::IsInstanceMethod, ArgTypes, + Info, ParamInfos, Required); } /// Arrange the argument and result information for the declaration or @@ -458,8 +456,8 @@ // non-variadic type. if (CanQual noProto = FTy.getAs()) { return arrangeLLVMFunctionInfo( - noProto->getReturnType(), /*instanceMethod=*/false, - /*chainCall=*/false, None, noProto->getExtInfo(), {},RequiredArgs::All); + noProto->getReturnType(), FnInfoOpts::None, + None, noProto->getExtInfo(), {},RequiredArgs::All); } return arrangeFreeFunctionType(FTy.castAs()); @@ -509,8 +507,7 @@ (MD->isVariadic() ? RequiredArgs(argTys.size()) : RequiredArgs::All); return arrangeLLVMFunctionInfo( - GetReturnType(MD->getReturnType()), /*instanceMethod=*/false, - /*chainCall=*/false, argTys, einfo, extParamInfos, required); + GetReturnType(MD->getReturnType()), FnInfoOpts::None, argTys, einfo, extParamInfos, required); } const CGFunctionInfo & @@ -520,8 +517,8 @@ FunctionType::ExtInfo einfo; return arrangeLLVMFunctionInfo( - GetReturnType(returnType), /*instanceMethod=*/false, - /*chainCall=*/false, argTypes, einfo, {}, RequiredArgs::All); + GetReturnType(returnType), FnInfoOpts::None, argTypes, einfo, {}, + RequiredArgs::All); } const CGFunctionInfo & @@ -546,8 +543,7 @@ assert(MD->isVirtual() && "only methods have thunks"); CanQual FTP = GetFormalType(MD); CanQualType ArgTys[] = {DeriveThisType(MD->getParent(), MD)}; - return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/false, - /*chainCall=*/false, ArgTys, + return arrangeLLVMFunctionInfo(Context.VoidTy, FnInfoOpts::None, ArgTys, FTP->getExtInfo(), {}, RequiredArgs(1)); } @@ -566,10 +562,8 @@ ArgTys.push_back(Context.IntTy); CallingConv CC = Context.getDefaultCallingConvention( /*IsVariadic=*/false, /*IsCXXMethod=*/true); - return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/true, - /*chainCall=*/false, ArgTys, - FunctionType::ExtInfo(CC), {}, - RequiredArgs::All); + return arrangeLLVMFunctionInfo(Context.VoidTy, FnInfoOpts::IsInstanceMethod, ArgTys, + FunctionType::ExtInfo(CC), {}, RequiredArgs::All); } /// Arrange a call as unto a free function, except possibly with an @@ -612,8 +606,8 @@ SmallVector argTypes; for (const auto &arg : args) argTypes.push_back(CGT.getContext().getCanonicalParamType(arg.Ty)); - return CGT.arrangeLLVMFunctionInfo(GetReturnType(fnType->getReturnType()), - /*instanceMethod=*/false, chainCall, + FnInfoOpts opts = chainCall ? FnInfoOpts::IsChainCall : FnInfoOpts::None; + return CGT.arrangeLLVMFunctionInfo(GetReturnType(fnType->getReturnType()), opts, argTypes, fnType->getExtInfo(), paramInfos, required); } @@ -645,8 +639,7 @@ auto paramInfos = getExtParameterInfosForCall(proto, 1, params.size()); auto argTypes = getArgTypesForDeclaration(Context, params); - return arrangeLLVMFunctionInfo(GetReturnType(proto->getReturnType()), - /*instanceMethod*/ false, /*chainCall*/ false, + return arrangeLLVMFunctionInfo(GetReturnType(proto->getReturnType()), FnInfoOpts::None, argTypes, proto->getExtInfo(), paramInfos, RequiredArgs::forPrototypePlus(proto, 1)); } @@ -659,8 +652,8 @@ for (const auto &Arg : args) argTypes.push_back(Context.getCanonicalParamType(Arg.Ty)); return arrangeLLVMFunctionInfo( - GetReturnType(resultType), /*instanceMethod=*/false, - /*chainCall=*/false, argTypes, FunctionType::ExtInfo(), + GetReturnType(resultType), FnInfoOpts::None, + argTypes, FunctionType::ExtInfo(), /*paramInfos=*/ {}, RequiredArgs::All); } @@ -670,16 +663,16 @@ auto argTypes = getArgTypesForDeclaration(Context, args); return arrangeLLVMFunctionInfo( - GetReturnType(resultType), /*instanceMethod=*/false, /*chainCall=*/false, - argTypes, FunctionType::ExtInfo(), {}, RequiredArgs::All); + GetReturnType(resultType), FnInfoOpts::None, argTypes, FunctionType::ExtInfo(), + {}, RequiredArgs::All); } const CGFunctionInfo & CodeGenTypes::arrangeBuiltinFunctionDeclaration(CanQualType resultType, ArrayRef argTypes) { return arrangeLLVMFunctionInfo( - resultType, /*instanceMethod=*/false, /*chainCall=*/false, - argTypes, FunctionType::ExtInfo(), {}, RequiredArgs::All); + resultType, FnInfoOpts::None, argTypes, FunctionType::ExtInfo(), {}, + RequiredArgs::All); } /// Arrange a call to a C++ method, passing the given arguments. @@ -703,14 +696,13 @@ FunctionType::ExtInfo info = proto->getExtInfo(); return arrangeLLVMFunctionInfo( - GetReturnType(proto->getReturnType()), /*instanceMethod=*/true, - /*chainCall=*/false, argTypes, info, paramInfos, required); + GetReturnType(proto->getReturnType()), FnInfoOpts::IsInstanceMethod, argTypes, + info, paramInfos, required); } const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() { return arrangeLLVMFunctionInfo( - getContext().VoidTy, /*instanceMethod=*/false, /*chainCall=*/false, - None, FunctionType::ExtInfo(), {}, RequiredArgs::All); + getContext().VoidTy, FnInfoOpts::None, None, FunctionType::ExtInfo(), {}, RequiredArgs::All); } const CGFunctionInfo & @@ -730,9 +722,15 @@ auto argTypes = getArgTypesForCall(Context, args); assert(signature.getRequiredArgs().allowsOptionalArgs()); + FnInfoOpts opts = FnInfoOpts::None; + if (signature.isInstanceMethod()) + opts |= FnInfoOpts::IsInstanceMethod; + if (signature.isChainCall()) + opts |= FnInfoOpts::IsChainCall; + if (signature.isDelegateCall()) + opts |= FnInfoOpts::IsDelegateCall; return arrangeLLVMFunctionInfo(signature.getReturnType(), - signature.isInstanceMethod(), - signature.isChainCall(), + opts, argTypes, signature.getExtInfo(), paramInfos, @@ -750,8 +748,7 @@ /// above functions ultimately defer to. const CGFunctionInfo & CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType, - bool instanceMethod, - bool chainCall, + FnInfoOpts opts, ArrayRef argTypes, FunctionType::ExtInfo info, ArrayRef paramInfos, @@ -761,7 +758,13 @@ // Lookup or create unique function info. llvm::FoldingSetNodeID ID; - CGFunctionInfo::Profile(ID, instanceMethod, chainCall, info, paramInfos, + bool isInstanceMethod = + (opts & FnInfoOpts::IsInstanceMethod) == FnInfoOpts::IsInstanceMethod; + bool isChainCall = + (opts & FnInfoOpts::IsChainCall) == FnInfoOpts::IsChainCall; + bool isDelegateCall = + (opts & FnInfoOpts::IsDelegateCall) == FnInfoOpts::IsDelegateCall; + CGFunctionInfo::Profile(ID, isInstanceMethod, isChainCall, info, paramInfos, required, resultType, argTypes); void *insertPos = nullptr; @@ -772,8 +775,9 @@ unsigned CC = ClangCallConvToLLVMCallConv(info.getCC()); // Construct the function info. We co-allocate the ArgInfos. - FI = CGFunctionInfo::create(CC, instanceMethod, chainCall, info, - paramInfos, resultType, argTypes, required); + FI = CGFunctionInfo::create(CC, isInstanceMethod, isChainCall, isDelegateCall, + info, paramInfos, resultType, + argTypes, required); FunctionInfos.InsertNode(FI, insertPos); bool inserted = FunctionsBeingProcessed.insert(FI).second; @@ -811,6 +815,7 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC, bool instanceMethod, bool chainCall, + bool delegateCall, const FunctionType::ExtInfo &info, ArrayRef paramInfos, CanQualType resultType, @@ -830,6 +835,7 @@ FI->ASTCallingConvention = info.getCC(); FI->InstanceMethod = instanceMethod; FI->ChainCall = chainCall; + FI->DelegateCall = delegateCall; FI->CmseNSCall = info.getCmseNSCall(); FI->NoReturn = info.getNoReturn(); FI->ReturnsRetained = info.getProducesResult(); @@ -3806,10 +3812,6 @@ QualType type = param->getType(); - if (isInAllocaArgument(CGM.getCXXABI(), type)) { - CGM.ErrorUnsupported(param, "forwarded non-trivially copyable parameter"); - } - // GetAddrOfLocalVar returns a pointer-to-pointer for references, // but the argument needs to be the original pointer. if (type->isReferenceType()) { diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -2935,13 +2935,16 @@ void CodeGenFunction::EmitForwardingCallToLambda( const CXXMethodDecl *callOperator, - CallArgList &callArgs) { + CallArgList &callArgs, + const CGFunctionInfo *calleeFnInfo, + llvm::Constant *calleePtr) { // Get the address of the call operator. - const CGFunctionInfo &calleeFnInfo = - CGM.getTypes().arrangeCXXMethodDeclaration(callOperator); - llvm::Constant *calleePtr = - CGM.GetAddrOfFunction(GlobalDecl(callOperator), - CGM.getTypes().GetFunctionType(calleeFnInfo)); + if (!calleeFnInfo) + calleeFnInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(callOperator); + + if (!calleePtr) + calleePtr = CGM.GetAddrOfFunction(GlobalDecl(callOperator), + CGM.getTypes().GetFunctionType(*calleeFnInfo)); // Prepare the return slot. const FunctionProtoType *FPT = @@ -2949,8 +2952,8 @@ QualType resultType = FPT->getReturnType(); ReturnValueSlot returnSlot; if (!resultType->isVoidType() && - calleeFnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect && - !hasScalarEvaluationKind(calleeFnInfo.getReturnType())) + calleeFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect && + !hasScalarEvaluationKind(calleeFnInfo->getReturnType())) returnSlot = ReturnValueSlot(ReturnValue, resultType.isVolatileQualified(), /*IsUnused=*/false, /*IsExternallyDestructed=*/true); @@ -2961,7 +2964,7 @@ // Now emit our call. auto callee = CGCallee::forDirect(calleePtr, GlobalDecl(callOperator)); - RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs); + RValue RV = EmitCall(*calleeFnInfo, callee, returnSlot, callArgs); // If necessary, copy the returned value into the slot. if (!resultType->isVoidType() && returnSlot.isNull()) { @@ -3003,6 +3006,19 @@ EmitForwardingCallToLambda(CallOp, CallArgs); } +static bool isInAllocaArg(CGCXXABI &ABI, QualType T) { + const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); + return RD && ABI.getRecordArgABI(RD) == CGCXXABI::RAA_DirectInMemory; +} + +static bool hasInAllocaArg(const TargetInfo &TI, CGCXXABI &ABI, const CXXMethodDecl *MD) { + return TI.getTriple().getArch() == llvm::Triple::x86 && + TI.getCXXABI().isMicrosoft() && + llvm::any_of(MD->parameters(), [&](ParmVarDecl *P) { + return isInAllocaArg(ABI, P->getType()); + }); +} + void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) { const CXXRecordDecl *Lambda = MD->getParent(); @@ -3031,6 +3047,17 @@ assert(CorrespondingCallOpSpecialization); CallOp = cast(CorrespondingCallOpSpecialization); } + + // Special lambda forwarding when there are inalloca parameters. + if (hasInAllocaArg(getTarget(), CGM.getCXXABI(), MD)) { + const CGFunctionInfo *ImplFnInfo = nullptr; + llvm::Function *ImplFn = nullptr; + EmitLambdaInAllocaImplFn(CallOp, &ImplFnInfo, &ImplFn); + + EmitForwardingCallToLambda(CallOp, CallArgs, ImplFnInfo, ImplFn); + return; + } + EmitForwardingCallToLambda(CallOp, CallArgs); } @@ -3042,5 +3069,82 @@ return; } + // If there are inalloca params, generate a new function containing the lambda body + // and make the invoker and original call operator call that function. + // Emit the new call operator here. + if (hasInAllocaArg(getTarget(), CGM.getCXXABI(), MD)) + EmitLambdaInAllocaCallOpFn(MD); + EmitLambdaDelegatingInvokeBody(MD); } + +void CodeGenFunction::EmitLambdaInAllocaImplFn(const CXXMethodDecl *CallOp, + const CGFunctionInfo **ImplFnInfo, + llvm::Function **ImplFn) { + const CGFunctionInfo &FnInfo = + CGM.getTypes().arrangeCXXMethodDeclaration(CallOp); + llvm::Function *CallOpFn = + cast(CGM.GetAddrOfFunction(GlobalDecl(CallOp))); + + // Emit impl function containing the original lambda body. + SmallVector ArgTypes; + for (auto I = FnInfo.arg_begin(); I != FnInfo.arg_end(); ++I) + ArgTypes.push_back(I->type); + *ImplFnInfo = &CGM.getTypes().arrangeLLVMFunctionInfo( + FnInfo.getReturnType(), FnInfoOpts::IsDelegateCall, ArgTypes, + FnInfo.getExtInfo(), {}, FnInfo.getRequiredArgs()); + + // Create mangled name as if this was a method named __impl. + StringRef CallOpName = CallOpFn->getName(); + std::string ImplName = + ("?__impl@" + CallOpName.drop_front(CallOpName.find_first_of("<"))).str(); + llvm::Function *Fn = CallOpFn->getParent()->getFunction(ImplName); + if (!Fn) { + Fn = llvm::Function::Create(CGM.getTypes().GetFunctionType(**ImplFnInfo), + llvm::GlobalValue::InternalLinkage, + ImplName, CGM.getModule()); + CGM.SetInternalFunctionAttributes(CallOp, Fn, **ImplFnInfo); + CodeGenFunction CGF(CGM); + CGF.CurGD = GlobalDecl(CallOp); + const FunctionDecl *FD = cast(CurGD.getDecl()); + + FunctionArgList Args; + QualType ResTy = CGF.BuildFunctionArgList(CurGD, Args); + + CGF.StartFunction(CurGD, ResTy, Fn, **ImplFnInfo, Args, + FD->getLocation(), FD->getLocation()); + CGF.EmitFunctionBody(FD->getBody()); + CGF.FinishFunction(); + } + *ImplFn = Fn; +} + +void CodeGenFunction::EmitLambdaInAllocaCallOpFn(const CXXMethodDecl *MD) { + const CXXMethodDecl *CallOp = MD->getParent()->getLambdaCallOperator(); + const CGFunctionInfo &FnInfo = + CGM.getTypes().arrangeCXXMethodDeclaration(CallOp); + llvm::Function *CallOpFn = + cast(CGM.GetAddrOfFunction(GlobalDecl(CallOp))); + + // Emit new call operator. + llvm::Function *Fn = llvm::Function::Create(CGM.getTypes().GetFunctionType(FnInfo), + llvm::GlobalValue::InternalLinkage, + "tmp", CGM.getModule()); + CGM.SetInternalFunctionAttributes(CallOp, Fn, FnInfo); + + CodeGenFunction CGF(CGM); + CGF.CurGD = GlobalDecl(CallOp); + const FunctionDecl *FD = cast(CGF.CurGD.getDecl()); + + FunctionArgList Args; + QualType ResTy = CGF.BuildFunctionArgList(CGF.CurGD, Args); + + CGF.StartFunction(CGF.CurGD, ResTy, Fn, FnInfo, Args, + FD->getLocation(), FD->getLocation()); + CGF.EmitLambdaDelegatingInvokeBody(CallOp); + CGF.FinishFunction(); + + CallOpFn->replaceAllUsesWith(Fn); + Fn->takeName(CallOpFn); + CallOpFn->eraseFromParent(); +} diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -278,7 +278,7 @@ } const CGFunctionInfo &FI = CGM.getTypes().arrangeLLVMFunctionInfo( - getContext().IntTy, /*instanceMethod=*/false, /*chainCall=*/false, + getContext().IntTy, FnInfoOpts::None, {getContext().IntTy}, FunctionType::ExtInfo(), {}, RequiredArgs::All); // Get the stub function type, int(*)(int,...). diff --git a/clang/lib/CodeGen/CodeGenABITypes.cpp b/clang/lib/CodeGen/CodeGenABITypes.cpp --- a/clang/lib/CodeGen/CodeGenABITypes.cpp +++ b/clang/lib/CodeGen/CodeGenABITypes.cpp @@ -65,9 +65,8 @@ ArrayRef argTypes, FunctionType::ExtInfo info, RequiredArgs args) { - return CGM.getTypes().arrangeLLVMFunctionInfo( - returnType, /*instanceMethod=*/false, /*chainCall=*/false, argTypes, - info, {}, args); + return CGM.getTypes().arrangeLLVMFunctionInfo(returnType, FnInfoOpts::None, + argTypes, info, {}, args); } ImplicitCXXConstructorArgs diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2219,10 +2219,16 @@ void EmitBlockWithFallThrough(llvm::BasicBlock *BB, const Stmt *S); void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator, - CallArgList &CallArgs); + CallArgList &CallArgs, + const CGFunctionInfo *CallOpFnInfo = nullptr, + llvm::Constant *CallOpFn = nullptr); void EmitLambdaBlockInvokeBody(); void EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD); void EmitLambdaStaticInvokeBody(const CXXMethodDecl *MD); + void EmitLambdaInAllocaCallOpFn(const CXXMethodDecl *MD); + void EmitLambdaInAllocaImplFn(const CXXMethodDecl *CallOp, + const CGFunctionInfo **ImplFnInfo, + llvm::Function **ImplFn); void EmitLambdaVLACapture(const VariableArrayType *VAT, LValue LV) { EmitStoreThroughLValue(RValue::get(VLASizeMap[VAT->getSizeExpr()]), LV); } diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h --- a/clang/lib/CodeGen/CodeGenTypes.h +++ b/clang/lib/CodeGen/CodeGenTypes.h @@ -260,8 +260,7 @@ /// /// \param argTypes - must all actually be canonical as params const CGFunctionInfo &arrangeLLVMFunctionInfo(CanQualType returnType, - bool instanceMethod, - bool chainCall, + FnInfoOpts opts, ArrayRef argTypes, FunctionType::ExtInfo info, ArrayRef paramInfos, diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -1187,7 +1187,7 @@ Class classify(QualType Ty) const; ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const; - ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const; + ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State, bool isDelegateCall) const; /// Updates the number of available free registers, returns /// true if any registers were allocated. @@ -1824,7 +1824,8 @@ } ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, - CCState &State) const { + CCState &State, + bool isDelegateCall) const { // FIXME: Set alignment on indirect arguments. bool IsFastCall = State.CC == llvm::CallingConv::X86_FastCall; bool IsRegCall = State.CC == llvm::CallingConv::X86_RegCall; @@ -1837,7 +1838,7 @@ const RecordType *RT = Ty->getAs(); if (RT) { CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); - if (RAA == CGCXXABI::RAA_Indirect) { + if (RAA == CGCXXABI::RAA_Indirect || isDelegateCall) { return getIndirectResult(Ty, false, State); } else if (RAA == CGCXXABI::RAA_DirectInMemory) { // The field index doesn't matter, we'll fix it up later. @@ -2014,7 +2015,7 @@ if (State.IsPreassigned.test(I)) continue; - Args[I].info = classifyArgumentType(Args[I].type, State); + Args[I].info = classifyArgumentType(Args[I].type, State, FI.isDelegateCall()); UsedInAlloca |= (Args[I].info.getKind() == ABIArgInfo::InAlloca); } diff --git a/clang/test/CodeGenCXX/inalloca-lambda.cpp b/clang/test/CodeGenCXX/inalloca-lambda.cpp --- a/clang/test/CodeGenCXX/inalloca-lambda.cpp +++ b/clang/test/CodeGenCXX/inalloca-lambda.cpp @@ -1,11 +1,50 @@ -// RUN: not %clang_cc1 -triple i686-windows-msvc -emit-llvm -o /dev/null %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -o - %s 2>&1 | FileCheck %s -// PR28299 -// CHECK: error: cannot compile this forwarded non-trivially copyable parameter yet - -class A { +struct A { + A(); A(const A &); + int x; }; -typedef void (*fptr_t)(A); -fptr_t fn1() { return [](A) {}; } +void decayToFp(int (*f)(A)); +void test() { + auto ld = [](A a) { + static int calls = 0; + ++calls; + return a.x + calls; + }; + decayToFp(ld); + ld(A{}); +} + +// CHECK: define internal noundef i32 +// CHECK-SAME: @"?__invoke@@?0??test@@YAXXZ@CA?A?@@UA@@@Z" +// CHECK-SAME: (ptr inalloca(<{ %struct.A }>) %[[ARG:.*]]) +// CHECK: %unused.capture = alloca %class.anon, align 1 +// CHECK: %[[VAR:.*]] = getelementptr inbounds <{ %struct.A }>, ptr %[[ARG]], i32 0, i32 0 +// CHECK: %call = call x86_thiscallcc noundef i32 +// CHECK-SAME: @"?__impl@@?0??test@@YAXXZ@QBE?A?@@UA@@@Z" +// CHECK-SAME: (ptr noundef %unused.capture, ptr noundef %[[VAR]]) +// CHECK: ret i32 %call + +// CHECK: define internal x86_thiscallcc noundef i32 +// CHECK-SAME: @"??R@?0??test@@YAXXZ@QBE?A?@@UA@@@Z" +// CHECK-SAME: (ptr noundef %this, ptr inalloca(<{ %struct.A }>) %[[ARG:.*]]) +// CHECK: %[[V:.*]] = getelementptr inbounds <{ %struct.A }>, ptr %[[ARG]], i32 0, i32 0 +// CHECK: %call = call x86_thiscallcc noundef i32 +// CHECK-SAME: @"?__impl@@?0??test@@YAXXZ@QBE?A?@@UA@@@Z" +// CHECK-SAME: (ptr noundef %unused.capture, ptr noundef %[[V]]) +// CHECK: define internal x86_thiscallcc noundef i32 +// CHECK-SAME: @"?__impl@@?0??test@@YAXXZ@QBE?A?@@UA@@@Z" +// CHECK-SAME: (ptr noundef %this, ptr noundef %[[ARG:.*]]) +// CHECK: %this.addr = alloca ptr, align 4 +// CHECK: store ptr %this, ptr %this.addr, align 4 +// CHECK: %this1 = load ptr, ptr %this.addr, align 4 +// CHECK: %{{.*}} = load i32, ptr @"?calls@?1???R +// CHECK: %inc = add nsw i32 %{{.*}}, 1 +// CHECK: store i32 %inc, ptr @"?calls@?1???R +// CHECK: %{{.*}} = getelementptr inbounds %struct.A, ptr %{{.*}}, i32 0, i32 0 +// CHECK: %{{.*}} = load i32, ptr %{{.*}}, align 4 +// CHECK: %{{.*}} = load i32, ptr @"?calls@?1???R +// CHECK: %add = add nsw i32 %{{.*}}, %{{.*}} +// CHECK: ret i32 %add