Skip to content

Commit

Permalink
Implement the __builtin_call_with_static_chain GNU extension.
Browse files Browse the repository at this point in the history
The extension has the following syntax:

  __builtin_call_with_static_chain(Call, Chain)
  where Call must be a function call expression and Chain must be of pointer type

This extension performs a function call Call with a static chain pointer
Chain passed to the callee in a designated register. This is useful for
calling foreign language functions whose ABI uses static chain pointers
(e.g. to implement closures).

Differential Revision: http://reviews.llvm.org/D6332

llvm-svn: 224167
  • Loading branch information
pcc committed Dec 12, 2014
1 parent 620fb22 commit f770683
Show file tree
Hide file tree
Showing 16 changed files with 275 additions and 71 deletions.
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Builtins.def
Expand Up @@ -497,6 +497,7 @@ BUILTIN(__builtin_unreachable, "v", "nr")
BUILTIN(__builtin_shufflevector, "v." , "nc")
BUILTIN(__builtin_convertvector, "v." , "nct")
BUILTIN(__builtin_alloca, "v*z" , "n")
BUILTIN(__builtin_call_with_static_chain, "v.", "nt")

// "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
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -6917,6 +6917,17 @@ def err_convertvector_non_vector_type : Error<
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">;
Expand Down
13 changes: 11 additions & 2 deletions clang/include/clang/CodeGen/CGFunctionInfo.h
Expand Up @@ -352,6 +352,9 @@ class CGFunctionInfo : public llvm::FoldingSetNode {
/// 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;

Expand All @@ -360,7 +363,7 @@ class CGFunctionInfo : public llvm::FoldingSetNode {

/// How many arguments to pass inreg.
unsigned HasRegParm : 1;
unsigned RegParm : 4;
unsigned RegParm : 3;

RequiredArgs Required;

Expand All @@ -380,7 +383,8 @@ class CGFunctionInfo : public llvm::FoldingSetNode {

public:
static CGFunctionInfo *create(unsigned llvmCC,
bool InstanceMethod,
bool instanceMethod,
bool chainCall,
const FunctionType::ExtInfo &extInfo,
CanQualType resultType,
ArrayRef<CanQualType> argTypes,
Expand Down Expand Up @@ -412,6 +416,8 @@ class CGFunctionInfo : public llvm::FoldingSetNode {

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
Expand Down Expand Up @@ -462,6 +468,7 @@ class CGFunctionInfo : public llvm::FoldingSetNode {
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddInteger(getASTCallingConvention());
ID.AddBoolean(InstanceMethod);
ID.AddBoolean(ChainCall);
ID.AddBoolean(NoReturn);
ID.AddBoolean(ReturnsRetained);
ID.AddBoolean(HasRegParm);
Expand All @@ -473,12 +480,14 @@ class CGFunctionInfo : public llvm::FoldingSetNode {
}
static void Profile(llvm::FoldingSetNodeID &ID,
bool InstanceMethod,
bool ChainCall,
const FunctionType::ExtInfo &info,
RequiredArgs required,
CanQualType resultType,
ArrayRef<CanQualType> argTypes) {
ID.AddInteger(info.getCC());
ID.AddBoolean(InstanceMethod);
ID.AddBoolean(ChainCall);
ID.AddBoolean(info.getNoReturn());
ID.AddBoolean(info.getProducesResult());
ID.AddBoolean(info.getHasRegParm());
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/CodeGen/CGBuiltin.cpp
Expand Up @@ -185,7 +185,8 @@ static llvm::Value *EmitOverflowIntrinsic(CodeGenFunction &CGF,
}

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()) &&
Expand Down Expand Up @@ -1566,6 +1567,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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<CallExpr>(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);
Expand Down
97 changes: 62 additions & 35 deletions clang/lib/CodeGen/CGCall.cpp
Expand Up @@ -83,22 +83,24 @@ CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> FTNP) {
// 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<CanQualType> &prefix,
CanQual<FunctionProtoType> FTP) {
RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, prefix.size());
// FIXME: Kill copy.
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);
}

Expand All @@ -107,7 +109,8 @@ arrangeLLVMFunctionInfo(CodeGenTypes &CGT, bool IsInstanceMethod,
const CGFunctionInfo &
CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionProtoType> FTP) {
SmallVector<CanQualType, 16> argTypes;
return ::arrangeLLVMFunctionInfo(*this, false, argTypes, FTP);
return ::arrangeLLVMFunctionInfo(*this, /*instanceMethod=*/false, argTypes,
FTP);
}

static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
Expand Down Expand Up @@ -219,7 +222,9 @@ CodeGenTypes::arrangeCXXStructorDeclaration(const CXXMethodDecl *MD,
: 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.
Expand All @@ -243,7 +248,9 @@ CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args,
: 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
Expand All @@ -262,8 +269,9 @@ CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) {
// non-variadic type.
if (isa<FunctionNoProtoType>(FTy)) {
CanQual<FunctionNoProtoType> noProto = FTy.getAs<FunctionNoProtoType>();
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<FunctionProtoType>(FTy));
Expand Down Expand Up @@ -307,8 +315,9 @@ CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
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 &
Expand All @@ -335,7 +344,8 @@ CodeGenTypes::arrangeMSMemberPointerThunk(const CXXMethodDecl *MD) {
assert(MD->isVirtual() && "only virtual memptrs have thunks");
CanQual<FunctionProtoType> 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));
}

Expand All @@ -346,7 +356,8 @@ arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
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.
Expand All @@ -368,8 +379,13 @@ arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
required = RequiredArgs(args.size());
}

return CGT.arrangeFreeFunctionCall(fnType->getReturnType(), args,
fnType->getExtInfo(), required);
// FIXME: Kill copy.
SmallVector<CanQualType, 16> 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
Expand All @@ -378,16 +394,19 @@ arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
/// 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
/// extra implicit argument.
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 &
Expand All @@ -399,8 +418,9 @@ CodeGenTypes::arrangeFreeFunctionCall(QualType resultType,
SmallVector<CanQualType, 16> 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.
Expand All @@ -414,8 +434,9 @@ CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args,
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(
Expand All @@ -428,21 +449,24 @@ const CGFunctionInfo &CodeGenTypes::arrangeFreeFunctionDeclaration(

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
/// of a given function type. This is the method which all of the
/// above functions ultimately defer to.
const CGFunctionInfo &
CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
bool IsInstanceMethod,
bool instanceMethod,
bool chainCall,
ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs required) {
Expand All @@ -453,17 +477,17 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,

// 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);
if (FI)
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;
Expand Down Expand Up @@ -491,7 +515,8 @@ CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType,
}

CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
bool IsInstanceMethod,
bool instanceMethod,
bool chainCall,
const FunctionType::ExtInfo &info,
CanQualType resultType,
ArrayRef<CanQualType> argTypes,
Expand All @@ -502,7 +527,8 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
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;
Expand Down Expand Up @@ -1497,7 +1523,6 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
getLLVMContext(), IRFunctionArgs.getInallocaArgNo() + 1, Attrs));
}


unsigned ArgNo = 0;
for (CGFunctionInfo::const_arg_iterator I = FI.arg_begin(),
E = FI.arg_end();
Expand Down Expand Up @@ -1525,7 +1550,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
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;

Expand Down

0 comments on commit f770683

Please sign in to comment.