16 changes: 11 additions & 5 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3049,7 +3049,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
const Decl *TargetDecl = E->getCalleeDecl();
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl)) {
if (unsigned builtinID = FD->getBuiltinID())
return EmitBuiltinExpr(FD, builtinID, E);
return EmitBuiltinExpr(FD, builtinID, E, ReturnValue);
}

if (const auto *CE = dyn_cast<CXXOperatorCallExpr>(E))
Expand Down Expand Up @@ -3286,7 +3286,7 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {

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() &&
Expand Down Expand Up @@ -3351,12 +3351,15 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
}

CallArgList Args;
if (Chain)
Args.add(RValue::get(Builder.CreateBitCast(Chain, CGM.VoidPtrTy)),
CGM.getContext().VoidPtrTy);
EmitCallArgs(Args, dyn_cast<FunctionProtoType>(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
Expand All @@ -3375,7 +3378,10 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
// 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<FunctionNoProtoType>(FnType)) {
//
// Chain calls use this same code path to add the invisible chain parameter
// to the function type.
if (isa<FunctionNoProtoType>(FnType) || Chain) {
llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo);
CalleeTy = CalleeTy->getPointerTo();
Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast");
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/CodeGen/CGExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1037,9 +1037,9 @@ static RValue EmitNewDeleteCall(CodeGenFunction &CGF,
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
Expand Down
36 changes: 16 additions & 20 deletions clang/lib/CodeGen/CGObjCMac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,9 @@ class ObjCCommonTypesHelper {
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");
}

Expand All @@ -264,10 +264,9 @@ class ObjCCommonTypesHelper {
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");
}

Expand All @@ -291,10 +290,9 @@ class ObjCCommonTypesHelper {
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";
Expand All @@ -319,10 +317,9 @@ class ObjCCommonTypesHelper {
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");
}

Expand All @@ -339,7 +336,7 @@ class ObjCCommonTypesHelper {
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));
Expand All @@ -353,10 +350,9 @@ class ObjCCommonTypesHelper {
SmallVector<CanQualType,1> 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");
}

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenABITypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,6 @@ CodeGenABITypes::arrangeFreeFunctionCall(CanQualType returnType,
FunctionType::ExtInfo info,
RequiredArgs args) {
return CGM->getTypes().arrangeLLVMFunctionInfo(
returnType, /*IsInstanceMethod=*/false, argTypes, info, args);
returnType, /*IsInstanceMethod=*/false, /*IsChainCall=*/false, argTypes,
info, args);
}
6 changes: 4 additions & 2 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -2284,7 +2284,8 @@ class CodeGenFunction : public CodeGenTypeCache {

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());

Expand Down Expand Up @@ -2351,7 +2352,8 @@ class CodeGenFunction : public CodeGenTypeCache {


RValue EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E);
unsigned BuiltinID, const CallExpr *E,
ReturnValueSlot ReturnValue);

RValue EmitBlockCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue);

Expand Down
6 changes: 4 additions & 2 deletions clang/lib/CodeGen/CodeGenTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ class CodeGenTypes {
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,
Expand All @@ -273,7 +274,8 @@ class CodeGenTypes {
///
/// \param argTypes - must all actually be canonical as params
const CGFunctionInfo &arrangeLLVMFunctionInfo(CanQualType returnType,
bool IsInstanceMethod,
bool instanceMethod,
bool chainCall,
ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs args);
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,10 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const {
}
}

// 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);
Expand Down Expand Up @@ -2687,6 +2691,10 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
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...
Expand Down
68 changes: 68 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,69 @@ static void SemaBuiltinMemChkCall(Sema &S, FunctionDecl *FDecl,
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 *Builtin = BuiltinCall->getCallee()->IgnoreImpCasts();
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<CallExpr>(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<FunctionDecl>(TargetDecl))
if (FD->getBuiltinID()) {
S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_builtin_call)
<< Call->getSourceRange();
return true;
}

if (isa<CXXPseudoDestructorExpr>(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;
}

QualType ReturnTy = CE->getCallReturnType();
QualType ArgTys[2] = { ReturnTy, ChainResult.get()->getType() };
QualType BuiltinTy = S.Context.getFunctionType(
ReturnTy, ArgTys, FunctionProtoType::ExtProtoInfo());
QualType BuiltinPtrTy = S.Context.getPointerType(BuiltinTy);

Builtin =
S.ImpCastExprToType(Builtin, BuiltinPtrTy, CK_BuiltinFnToFnPtr).get();

BuiltinCall->setType(CE->getType());
BuiltinCall->setValueKind(CE->getValueKind());
BuiltinCall->setObjectKind(CE->getObjectKind());
BuiltinCall->setCallee(Builtin);
BuiltinCall->setArg(1, ChainResult.get());

return false;
}

ExprResult
Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
CallExpr *TheCall) {
Expand Down Expand Up @@ -393,6 +456,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
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
Expand Down
39 changes: 39 additions & 0 deletions clang/test/CodeGenCXX/call-with-static-chain.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
11 changes: 11 additions & 0 deletions clang/test/Sema/call-with-static-chain.c
Original file line number Diff line number Diff line change
@@ -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}}
}
15 changes: 15 additions & 0 deletions clang/test/SemaCXX/call-with-static-chain.cpp
Original file line number Diff line number Diff line change
@@ -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}}
}