Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -497,6 +497,7 @@ BUILTIN(__builtin_shufflevector, "v." , "nc") BUILTIN(__builtin_convertvector, "v." , "nct") BUILTIN(__builtin_alloca, "v*z" , "n") +BUILTIN(__builtin_call_with_static_chain, "v.", "t") // "Overloaded" Atomic operator builtins. These are overloaded to support data // types of i8, i16, i32, i64, and i128. The front-end sees calls to the Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6918,6 +6918,17 @@ def err_convertvector_incompatible_vector : Error< "first two arguments to __builtin_convertvector must have the same number of elements">; +def err_first_argument_to_cwsc_not_call : Error< + "first argument to __builtin_call_with_static_chain must be a non-member call expression">; +def err_first_argument_to_cwsc_block_call : Error< + "first argument to __builtin_call_with_static_chain must not be a block call">; +def err_first_argument_to_cwsc_builtin_call : Error< + "first argument to __builtin_call_with_static_chain must not be a builtin call">; +def err_first_argument_to_cwsc_pdtor_call : Error< + "first argument to __builtin_call_with_static_chain must not be a pseudo-destructor call">; +def err_second_argument_to_cwsc_not_pointer : Error< + "second argument to __builtin_call_with_static_chain must be of pointer type">; + def err_vector_incorrect_num_initializers : Error< "%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">; def err_altivec_empty_initializer : Error<"expected initializer">; Index: include/clang/CodeGen/CGFunctionInfo.h =================================================================== --- include/clang/CodeGen/CGFunctionInfo.h +++ include/clang/CodeGen/CGFunctionInfo.h @@ -352,6 +352,9 @@ /// Whether this is an instance method. unsigned InstanceMethod : 1; + /// Whether this is a chain call. + unsigned ChainCall : 1; + /// Whether this function is noreturn. unsigned NoReturn : 1; @@ -360,7 +363,7 @@ /// How many arguments to pass inreg. unsigned HasRegParm : 1; - unsigned RegParm : 4; + unsigned RegParm : 3; RequiredArgs Required; @@ -380,7 +383,8 @@ public: static CGFunctionInfo *create(unsigned llvmCC, - bool InstanceMethod, + bool instanceMethod, + bool chainCall, const FunctionType::ExtInfo &extInfo, CanQualType resultType, ArrayRef argTypes, @@ -412,6 +416,8 @@ bool isInstanceMethod() const { return InstanceMethod; } + bool isChainCall() const { return ChainCall; } + bool isNoReturn() const { return NoReturn; } /// In ARC, whether this function retains its return value. This @@ -462,6 +468,7 @@ void Profile(llvm::FoldingSetNodeID &ID) { ID.AddInteger(getASTCallingConvention()); ID.AddBoolean(InstanceMethod); + ID.AddBoolean(ChainCall); ID.AddBoolean(NoReturn); ID.AddBoolean(ReturnsRetained); ID.AddBoolean(HasRegParm); @@ -473,12 +480,14 @@ } static void Profile(llvm::FoldingSetNodeID &ID, bool InstanceMethod, + bool ChainCall, const FunctionType::ExtInfo &info, RequiredArgs required, CanQualType resultType, ArrayRef argTypes) { ID.AddInteger(info.getCC()); ID.AddBoolean(InstanceMethod); + ID.AddBoolean(ChainCall); ID.AddBoolean(info.getNoReturn()); ID.AddBoolean(info.getProducesResult()); ID.AddBoolean(info.getHasRegParm()); Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -185,7 +185,8 @@ } RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, - unsigned BuiltinID, const CallExpr *E) { + unsigned BuiltinID, const CallExpr *E, + ReturnValueSlot ReturnValue) { // See if we can constant fold this builtin. If so, don't emit it at all. Expr::EvalResult Result; if (E->EvaluateAsRValue(Result, CGM.getContext()) && @@ -1566,6 +1567,13 @@ case Builtin::BI__noop: // __noop always evaluates to an integer literal zero. return RValue::get(ConstantInt::get(IntTy, 0)); + case Builtin::BI__builtin_call_with_static_chain: { + const CallExpr *Call = cast(E->getArg(0)); + const Expr *Chain = E->getArg(1); + return EmitCall(Call->getCallee()->getType(), + EmitScalarExpr(Call->getCallee()), Call, ReturnValue, + Call->getCalleeDecl(), EmitScalarExpr(Chain)); + } case Builtin::BI_InterlockedExchange: case Builtin::BI_InterlockedExchangePointer: return EmitBinaryAtomic(*this, llvm::AtomicRMWInst::Xchg, E); Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -83,14 +83,15 @@ // When translating an unprototyped function type, always use a // variadic type. return arrangeLLVMFunctionInfo(FTNP->getReturnType().getUnqualifiedType(), - false, None, FTNP->getExtInfo(), - RequiredArgs(0)); + /*instanceMethod=*/false, + /*chainCall=*/false, None, + FTNP->getExtInfo(), RequiredArgs(0)); } /// Arrange the LLVM function layout for a value of the given function /// type, on top of any implicit parameters already stored. static const CGFunctionInfo & -arrangeLLVMFunctionInfo(CodeGenTypes &CGT, bool IsInstanceMethod, +arrangeLLVMFunctionInfo(CodeGenTypes &CGT, bool instanceMethod, SmallVectorImpl &prefix, CanQual FTP) { RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, prefix.size()); @@ -98,7 +99,8 @@ for (unsigned i = 0, e = FTP->getNumParams(); i != e; ++i) prefix.push_back(FTP->getParamType(i)); CanQualType resultType = FTP->getReturnType().getUnqualifiedType(); - return CGT.arrangeLLVMFunctionInfo(resultType, IsInstanceMethod, prefix, + return CGT.arrangeLLVMFunctionInfo(resultType, instanceMethod, + /*chainCall=*/false, prefix, FTP->getExtInfo(), required); } @@ -107,7 +109,8 @@ const CGFunctionInfo & CodeGenTypes::arrangeFreeFunctionType(CanQual FTP) { SmallVector argTypes; - return ::arrangeLLVMFunctionInfo(*this, false, argTypes, FTP); + return ::arrangeLLVMFunctionInfo(*this, /*instanceMethod=*/false, argTypes, + FTP); } static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) { @@ -219,7 +222,9 @@ : TheCXXABI.hasMostDerivedReturn(GD) ? CGM.getContext().VoidPtrTy : Context.VoidTy; - return arrangeLLVMFunctionInfo(resultType, true, argTypes, extInfo, required); + return arrangeLLVMFunctionInfo(resultType, /*instanceMethod=*/true, + /*chainCall=*/false, argTypes, extInfo, + required); } /// Arrange a call to a C++ method, passing the given arguments. @@ -243,7 +248,9 @@ : Context.VoidTy; FunctionType::ExtInfo Info = FPT->getExtInfo(); - return arrangeLLVMFunctionInfo(ResultType, true, ArgTypes, Info, Required); + return arrangeLLVMFunctionInfo(ResultType, /*instanceMethod=*/true, + /*chainCall=*/false, ArgTypes, Info, + Required); } /// Arrange the argument and result information for the declaration or @@ -262,8 +269,9 @@ // non-variadic type. if (isa(FTy)) { CanQual noProto = FTy.getAs(); - return arrangeLLVMFunctionInfo(noProto->getReturnType(), false, None, - noProto->getExtInfo(), RequiredArgs::All); + return arrangeLLVMFunctionInfo( + noProto->getReturnType(), /*instanceMethod=*/false, + /*chainCall=*/false, None, noProto->getExtInfo(), RequiredArgs::All); } assert(isa(FTy)); @@ -307,8 +315,9 @@ RequiredArgs required = (MD->isVariadic() ? RequiredArgs(argTys.size()) : RequiredArgs::All); - return arrangeLLVMFunctionInfo(GetReturnType(MD->getReturnType()), false, - argTys, einfo, required); + return arrangeLLVMFunctionInfo( + GetReturnType(MD->getReturnType()), /*instanceMethod=*/false, + /*chainCall=*/false, argTys, einfo, required); } const CGFunctionInfo & @@ -335,7 +344,8 @@ assert(MD->isVirtual() && "only virtual memptrs have thunks"); CanQual FTP = GetFormalType(MD); CanQualType ArgTys[] = { GetThisType(Context, MD->getParent()) }; - return arrangeLLVMFunctionInfo(Context.VoidTy, false, ArgTys, + return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/false, + /*chainCall=*/false, ArgTys, FTP->getExtInfo(), RequiredArgs(1)); } @@ -346,7 +356,8 @@ CodeGenModule &CGM, const CallArgList &args, const FunctionType *fnType, - unsigned numExtraRequiredArgs) { + unsigned numExtraRequiredArgs, + bool chainCall) { assert(args.size() >= numExtraRequiredArgs); // In most cases, there are no optional arguments. @@ -368,8 +379,13 @@ required = RequiredArgs(args.size()); } - return CGT.arrangeFreeFunctionCall(fnType->getReturnType(), args, - fnType->getExtInfo(), required); + // FIXME: Kill copy. + SmallVector argTypes; + for (const auto &arg : args) + argTypes.push_back(CGT.getContext().getCanonicalParamType(arg.Ty)); + return CGT.arrangeLLVMFunctionInfo(GetReturnType(fnType->getReturnType()), + /*instanceMethod=*/false, chainCall, + argTypes, fnType->getExtInfo(), required); } /// Figure out the rules for calling a function with the given formal @@ -378,8 +394,10 @@ /// target-dependent in crazy ways. const CGFunctionInfo & CodeGenTypes::arrangeFreeFunctionCall(const CallArgList &args, - const FunctionType *fnType) { - return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, 0); + const FunctionType *fnType, + bool chainCall) { + return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, + chainCall ? 1 : 0, chainCall); } /// A block function call is essentially a free-function call with an @@ -387,7 +405,8 @@ const CGFunctionInfo & CodeGenTypes::arrangeBlockFunctionCall(const CallArgList &args, const FunctionType *fnType) { - return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, 1); + return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, 1, + /*chainCall=*/false); } const CGFunctionInfo & @@ -399,8 +418,9 @@ SmallVector argTypes; for (const auto &Arg : args) argTypes.push_back(Context.getCanonicalParamType(Arg.Ty)); - return arrangeLLVMFunctionInfo(GetReturnType(resultType), false, argTypes, - info, required); + return arrangeLLVMFunctionInfo( + GetReturnType(resultType), /*instanceMethod=*/false, + /*chainCall=*/false, argTypes, info, required); } /// Arrange a call to a C++ method, passing the given arguments. @@ -414,8 +434,9 @@ argTypes.push_back(Context.getCanonicalParamType(Arg.Ty)); FunctionType::ExtInfo info = FPT->getExtInfo(); - return arrangeLLVMFunctionInfo(GetReturnType(FPT->getReturnType()), true, - argTypes, info, required); + return arrangeLLVMFunctionInfo( + GetReturnType(FPT->getReturnType()), /*instanceMethod=*/true, + /*chainCall=*/false, argTypes, info, required); } const CGFunctionInfo &CodeGenTypes::arrangeFreeFunctionDeclaration( @@ -428,13 +449,15 @@ RequiredArgs required = (isVariadic ? RequiredArgs(args.size()) : RequiredArgs::All); - return arrangeLLVMFunctionInfo(GetReturnType(resultType), false, argTypes, info, - required); + return arrangeLLVMFunctionInfo( + GetReturnType(resultType), /*instanceMethod=*/false, + /*chainCall=*/false, argTypes, info, required); } const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() { - return arrangeLLVMFunctionInfo(getContext().VoidTy, false, None, - FunctionType::ExtInfo(), RequiredArgs::All); + return arrangeLLVMFunctionInfo( + getContext().VoidTy, /*instanceMethod=*/false, /*chainCall=*/false, + None, FunctionType::ExtInfo(), RequiredArgs::All); } /// Arrange the argument and result information for an abstract value @@ -442,7 +465,8 @@ /// above functions ultimately defer to. const CGFunctionInfo & CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType, - bool IsInstanceMethod, + bool instanceMethod, + bool chainCall, ArrayRef argTypes, FunctionType::ExtInfo info, RequiredArgs required) { @@ -453,8 +477,8 @@ // Lookup or create unique function info. llvm::FoldingSetNodeID ID; - CGFunctionInfo::Profile(ID, IsInstanceMethod, info, required, resultType, - argTypes); + CGFunctionInfo::Profile(ID, instanceMethod, chainCall, info, required, + resultType, argTypes); void *insertPos = nullptr; CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, insertPos); @@ -462,8 +486,8 @@ return *FI; // Construct the function info. We co-allocate the ArgInfos. - FI = CGFunctionInfo::create(CC, IsInstanceMethod, info, resultType, argTypes, - required); + FI = CGFunctionInfo::create(CC, instanceMethod, chainCall, info, + resultType, argTypes, required); FunctionInfos.InsertNode(FI, insertPos); bool inserted = FunctionsBeingProcessed.insert(FI).second; @@ -491,7 +515,8 @@ } CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC, - bool IsInstanceMethod, + bool instanceMethod, + bool chainCall, const FunctionType::ExtInfo &info, CanQualType resultType, ArrayRef argTypes, @@ -502,7 +527,8 @@ FI->CallingConvention = llvmCC; FI->EffectiveCallingConvention = llvmCC; FI->ASTCallingConvention = info.getCC(); - FI->InstanceMethod = IsInstanceMethod; + FI->InstanceMethod = instanceMethod; + FI->ChainCall = chainCall; FI->NoReturn = info.getNoReturn(); FI->ReturnsRetained = info.getProducesResult(); FI->Required = required; @@ -1490,7 +1516,6 @@ getLLVMContext(), IRFunctionArgs.getInallocaArgNo() + 1, Attrs)); } - unsigned ArgNo = 0; for (CGFunctionInfo::const_arg_iterator I = FI.arg_begin(), E = FI.arg_end(); @@ -1518,7 +1543,9 @@ Attrs.addAttribute(llvm::Attribute::ZExt); // FALL THROUGH case ABIArgInfo::Direct: - if (AI.getInReg()) + if (ArgNo == 0 && FI.isChainCall()) + Attrs.addAttribute(llvm::Attribute::Nest); + else if (AI.getInReg()) Attrs.addAttribute(llvm::Attribute::InReg); break; Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -3032,7 +3032,7 @@ const Decl *TargetDecl = E->getCalleeDecl(); if (const FunctionDecl *FD = dyn_cast_or_null(TargetDecl)) { if (unsigned builtinID = FD->getBuiltinID()) - return EmitBuiltinExpr(FD, builtinID, E); + return EmitBuiltinExpr(FD, builtinID, E, ReturnValue); } if (const auto *CE = dyn_cast(E)) @@ -3269,7 +3269,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, const CallExpr *E, ReturnValueSlot ReturnValue, - const Decl *TargetDecl) { + const Decl *TargetDecl, llvm::Value *Chain) { // Get the actual function type. The callee type will always be a pointer to // function type or a block pointer type. assert(CalleeType->isFunctionPointerType() && @@ -3334,12 +3334,15 @@ } CallArgList Args; + if (Chain) + Args.add(RValue::get(Builder.CreateBitCast(Chain, CGM.VoidPtrTy)), + CGM.getContext().VoidPtrTy); EmitCallArgs(Args, dyn_cast(FnType), E->arg_begin(), E->arg_end(), E->getDirectCallee(), /*ParamsToSkip*/ 0, ForceColumnInfo); - const CGFunctionInfo &FnInfo = - CGM.getTypes().arrangeFreeFunctionCall(Args, FnType); + const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall( + Args, FnType, /*isChainCall=*/Chain); // C99 6.5.2.2p6: // If the expression that denotes the called function has a type @@ -3358,7 +3361,10 @@ // through an unprototyped function type works like a *non-variadic* // call. The way we make this work is to cast to the exact type // of the promoted arguments. - if (isa(FnType)) { + // + // Chain calls use this same code path to add the invisible chain parameter + // to the function type. + if (isa(FnType) || Chain) { llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo); CalleeTy = CalleeTy->getPointerTo(); Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast"); Index: lib/CodeGen/CGExprCXX.cpp =================================================================== --- lib/CodeGen/CGExprCXX.cpp +++ lib/CodeGen/CGExprCXX.cpp @@ -1033,9 +1033,9 @@ llvm::Instruction *CallOrInvoke; llvm::Value *CalleeAddr = CGF.CGM.GetAddrOfFunction(Callee); RValue RV = - CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall(Args, CalleeType), - CalleeAddr, ReturnValueSlot(), Args, - Callee, &CallOrInvoke); + CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall( + Args, CalleeType, /*chainCall=*/false), + CalleeAddr, ReturnValueSlot(), Args, Callee, &CallOrInvoke); /// C++1y [expr.new]p10: /// [In a new-expression,] an implementation is allowed to omit a call Index: lib/CodeGen/CGObjCMac.cpp =================================================================== --- lib/CodeGen/CGObjCMac.cpp +++ lib/CodeGen/CGObjCMac.cpp @@ -244,9 +244,9 @@ Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified()); Params.push_back(Ctx.BoolTy); llvm::FunctionType *FTy = - Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(IdType, false, Params, - FunctionType::ExtInfo(), - RequiredArgs::All)); + Types.GetFunctionType(Types.arrangeLLVMFunctionInfo( + IdType, false, false, Params, FunctionType::ExtInfo(), + RequiredArgs::All)); return CGM.CreateRuntimeFunction(FTy, "objc_getProperty"); } @@ -264,10 +264,9 @@ Params.push_back(Ctx.BoolTy); Params.push_back(Ctx.BoolTy); llvm::FunctionType *FTy = - Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false, - Params, - FunctionType::ExtInfo(), - RequiredArgs::All)); + Types.GetFunctionType(Types.arrangeLLVMFunctionInfo( + Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(), + RequiredArgs::All)); return CGM.CreateRuntimeFunction(FTy, "objc_setProperty"); } @@ -291,10 +290,9 @@ Params.push_back(IdType); Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified()); llvm::FunctionType *FTy = - Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false, - Params, - FunctionType::ExtInfo(), - RequiredArgs::All)); + Types.GetFunctionType(Types.arrangeLLVMFunctionInfo( + Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(), + RequiredArgs::All)); const char *name; if (atomic && copy) name = "objc_setProperty_atomic_copy"; @@ -319,10 +317,9 @@ Params.push_back(Ctx.BoolTy); Params.push_back(Ctx.BoolTy); llvm::FunctionType *FTy = - Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false, - Params, - FunctionType::ExtInfo(), - RequiredArgs::All)); + Types.GetFunctionType(Types.arrangeLLVMFunctionInfo( + Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(), + RequiredArgs::All)); return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct"); } @@ -339,7 +336,7 @@ Params.push_back(Ctx.VoidPtrTy); Params.push_back(Ctx.VoidPtrTy); llvm::FunctionType *FTy = - Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false, + Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(), RequiredArgs::All)); @@ -353,10 +350,9 @@ SmallVector Params; Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType())); llvm::FunctionType *FTy = - Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false, - Params, - FunctionType::ExtInfo(), - RequiredArgs::All)); + Types.GetFunctionType(Types.arrangeLLVMFunctionInfo( + Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(), + RequiredArgs::All)); return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation"); } Index: lib/CodeGen/CodeGenABITypes.cpp =================================================================== --- lib/CodeGen/CodeGenABITypes.cpp +++ lib/CodeGen/CodeGenABITypes.cpp @@ -67,5 +67,6 @@ FunctionType::ExtInfo info, RequiredArgs args) { return CGM->getTypes().arrangeLLVMFunctionInfo( - returnType, /*IsInstanceMethod=*/false, argTypes, info, args); + returnType, /*IsInstanceMethod=*/false, /*IsChainCall=*/false, argTypes, + info, args); } Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -2281,7 +2281,8 @@ RValue EmitCall(QualType FnType, llvm::Value *Callee, const CallExpr *E, ReturnValueSlot ReturnValue, - const Decl *TargetDecl = nullptr); + const Decl *TargetDecl = nullptr, + llvm::Value *Chain = nullptr); RValue EmitCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue = ReturnValueSlot()); @@ -2348,7 +2349,8 @@ RValue EmitBuiltinExpr(const FunctionDecl *FD, - unsigned BuiltinID, const CallExpr *E); + unsigned BuiltinID, const CallExpr *E, + ReturnValueSlot ReturnValue); RValue EmitBlockCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue); Index: lib/CodeGen/CodeGenTypes.h =================================================================== --- lib/CodeGen/CodeGenTypes.h +++ lib/CodeGen/CodeGenTypes.h @@ -248,7 +248,8 @@ CXXCtorType CtorKind, unsigned ExtraArgs); const CGFunctionInfo &arrangeFreeFunctionCall(const CallArgList &Args, - const FunctionType *Ty); + const FunctionType *Ty, + bool ChainCall); const CGFunctionInfo &arrangeFreeFunctionCall(QualType ResTy, const CallArgList &args, FunctionType::ExtInfo info, @@ -273,7 +274,8 @@ /// /// \param argTypes - must all actually be canonical as params const CGFunctionInfo &arrangeLLVMFunctionInfo(CanQualType returnType, - bool IsInstanceMethod, + bool instanceMethod, + bool chainCall, ArrayRef argTypes, FunctionType::ExtInfo info, RequiredArgs args); Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -1146,6 +1146,10 @@ } } + // The chain argument effectively gives us another free register. + if (FI.isChainCall()) + ++State.FreeRegs; + bool UsedInAlloca = false; for (auto &I : FI.arguments()) { I.info = classifyArgumentType(I.type, State); @@ -2687,6 +2691,10 @@ if (FI.getReturnInfo().isIndirect()) --freeIntRegs; + // The chain argument effectively gives us another free register. + if (FI.isChainCall()) + ++freeIntRegs; + unsigned NumRequiredArgs = FI.getNumRequiredArgs(); // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers // get assigned (in left-to-right order) for passing as follows... Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -139,6 +139,59 @@ S.Diag(SL, diag::warn_memcpy_chk_overflow) << SR << FnName; } +static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { + if (checkArgCount(S, BuiltinCall, 2)) + return true; + + SourceLocation BuiltinLoc = BuiltinCall->getLocStart(); + Expr *Call = BuiltinCall->getArg(0); + Expr *Chain = BuiltinCall->getArg(1); + + if (Call->getStmtClass() != Stmt::CallExprClass) { + S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_not_call) + << Call->getSourceRange(); + return true; + } + + auto CE = cast(Call); + if (CE->getCallee()->getType()->isBlockPointerType()) { + S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_block_call) + << Call->getSourceRange(); + return true; + } + + const Decl *TargetDecl = CE->getCalleeDecl(); + if (const FunctionDecl *FD = dyn_cast_or_null(TargetDecl)) + if (FD->getBuiltinID()) { + S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_builtin_call) + << Call->getSourceRange(); + return true; + } + + if (isa(CE->getCallee()->IgnoreParens())) { + S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_pdtor_call) + << Call->getSourceRange(); + return true; + } + + ExprResult ChainResult = S.UsualUnaryConversions(Chain); + if (ChainResult.isInvalid()) + return true; + if (!ChainResult.get()->getType()->isPointerType()) { + S.Diag(BuiltinLoc, diag::err_second_argument_to_cwsc_not_pointer) + << Chain->getSourceRange(); + return true; + } + + BuiltinCall->setType(CE->getType()); + BuiltinCall->getCallee()->setType(CE->getCallee()->getType()); + BuiltinCall->setValueKind(CE->getValueKind()); + BuiltinCall->setObjectKind(CE->getObjectKind()); + BuiltinCall->setArg(1, ChainResult.get()); + + return false; +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -393,6 +446,11 @@ case Builtin::BI__builtin___vsnprintf_chk: SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3); break; + + case Builtin::BI__builtin_call_with_static_chain: + if (SemaBuiltinCallWithStaticChain(*this, TheCall)) + return ExprError(); + break; } // Since the target specific builtins for each arch overlap, only check those Index: test/CodeGenCXX/call-with-static-chain.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/call-with-static-chain.cpp @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=CHECK32 %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=CHECK64 %s + +struct A { + long x, y; +}; + +struct B { + long x, y, z, w; +}; + +extern "C" { + +int f1(A, A, A, A); +B f2(void); +_Complex float f3(void); +A &f4(); + +} + +void test() { + A a; + + // CHECK32: call i32 bitcast (i32 (%struct.A*, %struct.A*, %struct.A*, %struct.A*)* @f1 to i32 (i8*, %struct.A*, %struct.A*, %struct.A*, %struct.A*)*)(i8* nest bitcast (i32 (%struct.A*, %struct.A*, %struct.A*, %struct.A*)* @f1 to i8*) + // CHECK64: call i32 bitcast (i32 (i64, i64, i64, i64, i64, i64, %struct.A*)* @f1 to i32 (i8*, i64, i64, i64, i64, i64, i64, %struct.A*)*)(i8* nest bitcast (i32 (i64, i64, i64, i64, i64, i64, %struct.A*)* @f1 to i8*) + __builtin_call_with_static_chain(f1(a, a, a, a), f1); + + // CHECK32: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*)) + // CHECK64: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*)) + __builtin_call_with_static_chain(f2(), f2); + + // CHECK32: call i64 bitcast (i64 ()* @f3 to i64 (i8*)*)(i8* nest bitcast (i64 ()* @f3 to i8*)) + // CHECK64: call <2 x float> bitcast (<2 x float> ()* @f3 to <2 x float> (i8*)*)(i8* nest bitcast (<2 x float> ()* @f3 to i8*)) + __builtin_call_with_static_chain(f3(), f3); + + // CHECK32: call dereferenceable(8) %struct.A* bitcast (%struct.A* ()* @f4 to %struct.A* (i8*)*)(i8* nest bitcast (%struct.A* ()* @f4 to i8*)) + // CHECK64: call dereferenceable(16) %struct.A* bitcast (%struct.A* ()* @f4 to %struct.A* (i8*)*)(i8* nest bitcast (%struct.A* ()* @f4 to i8*)) + __builtin_call_with_static_chain(f4(), f4); +} Index: test/Sema/call-with-static-chain.c =================================================================== --- /dev/null +++ test/Sema/call-with-static-chain.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s + +void f(); + +void g() { + __builtin_call_with_static_chain(f(), f); + __builtin_call_with_static_chain(f, f); // expected-error {{first argument to __builtin_call_with_static_chain must be a non-member call expression}} + __builtin_call_with_static_chain(^{}(), f); // expected-error {{first argument to __builtin_call_with_static_chain must not be a block call}} + __builtin_call_with_static_chain(__builtin_unreachable(), f); // expected-error {{first argument to __builtin_call_with_static_chain must not be a builtin call}} + __builtin_call_with_static_chain(f(), 42); // expected-error {{second argument to __builtin_call_with_static_chain must be of pointer type}} +} Index: test/SemaCXX/call-with-static-chain.cpp =================================================================== --- /dev/null +++ test/SemaCXX/call-with-static-chain.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +int &f(); + +struct A { + void f(); +}; + +typedef int I; + +void g() { + __builtin_call_with_static_chain(f(), f) = 42; + __builtin_call_with_static_chain(A().f(), f); // expected-error {{first argument to __builtin_call_with_static_chain must be a non-member call expression}} + __builtin_call_with_static_chain((42).~I(), f); // expected-error {{first argument to __builtin_call_with_static_chain must not be a pseudo-destructor call}} +}