Whether an argument is required (in contrast with being an

optional argument passed through the variadic ellipsis)
potentially affects how we need to lower it.  Propagate
this information down to the various getFunctionInfo(...)
overloads on CodeGenTypes.  Furthermore, rename those
overloads to clarify their distinct purposes, and make
sure we're calling the right one in the right place.
This has a nice side-effect of making it easier to construct
a function type, since the 'variadic' bit is no longer
separable.

This shouldn't really change anything for our existing
platforms, with one minor exception --- we should now call
variadic ObjC methods with the ... in the "right place"
(see the test case), which I guess matters for anyone
running GNUStep on MIPS.  Mostly it's just a substantial
clean-up.

llvm-svn: 150788
This commit is contained in:
John McCall 2012-02-17 03:33:10 +00:00
parent c833deaa09
commit a729c62b81
23 changed files with 670 additions and 416 deletions

View File

@ -855,11 +855,11 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
llvm::Value *Func = Builder.CreateLoad(FuncPtr);
const FunctionType *FuncTy = FnType->castAs<FunctionType>();
const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(Args, FuncTy);
const CGFunctionInfo &FnInfo =
CGM.getTypes().arrangeFunctionCall(Args, FuncTy);
// Cast the function pointer to the right type.
llvm::Type *BlockFTy =
CGM.getTypes().GetFunctionType(FnInfo, false);
llvm::Type *BlockFTy = CGM.getTypes().GetFunctionType(FnInfo);
llvm::Type *BlockFTyPtr = llvm::PointerType::getUnqual(BlockFTy);
Func = Builder.CreateBitCast(Func, BlockFTyPtr);
@ -1013,16 +1013,15 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
args.push_back(*i);
// Create the function declaration.
const FunctionProtoType *fnType =
cast<FunctionProtoType>(blockInfo.getBlockExpr()->getFunctionType());
const FunctionProtoType *fnType = blockInfo.getBlockExpr()->getFunctionType();
const CGFunctionInfo &fnInfo =
CGM.getTypes().getFunctionInfo(fnType->getResultType(), args,
fnType->getExtInfo());
CGM.getTypes().arrangeFunctionDeclaration(fnType->getResultType(), args,
fnType->getExtInfo(),
fnType->isVariadic());
if (CGM.ReturnTypeUsesSRet(fnInfo))
blockInfo.UsesStret = true;
llvm::FunctionType *fnLLVMType =
CGM.getTypes().GetFunctionType(fnInfo, fnType->isVariadic());
llvm::FunctionType *fnLLVMType = CGM.getTypes().GetFunctionType(fnInfo);
MangleBuffer name;
CGM.getBlockMangledName(GD, name, blockDecl);
@ -1164,11 +1163,13 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
args.push_back(&srcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(C.VoidTy, args, FunctionType::ExtInfo());
CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
FunctionType::ExtInfo(),
/*variadic*/ false);
// FIXME: it would be nice if these were mergeable with things with
// identical semantics.
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
@ -1279,11 +1280,13 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
args.push_back(&srcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(C.VoidTy, args, FunctionType::ExtInfo());
CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
FunctionType::ExtInfo(),
/*variadic*/ false);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
@ -1557,10 +1560,12 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
args.push_back(&src);
const CGFunctionInfo &FI =
CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
CGF.CGM.getTypes().arrangeFunctionDeclaration(R, args,
FunctionType::ExtInfo(),
/*variadic*/ false);
CodeGenTypes &Types = CGF.CGM.getTypes();
llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
llvm::FunctionType *LTy = Types.GetFunctionType(FI);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
@ -1625,10 +1630,12 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
args.push_back(&src);
const CGFunctionInfo &FI =
CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo());
CGF.CGM.getTypes().arrangeFunctionDeclaration(R, args,
FunctionType::ExtInfo(),
/*variadic*/ false);
CodeGenTypes &Types = CGF.CGM.getTypes();
llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
llvm::FunctionType *LTy = Types.GetFunctionType(FI);
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.

View File

@ -196,7 +196,8 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor,
GlobalDecl(ctor, Ctor_Base)))
return;
const CGFunctionInfo &fnInfo = getTypes().getFunctionInfo(ctor, ctorType);
const CGFunctionInfo &fnInfo =
getTypes().arrangeCXXConstructorDeclaration(ctor, ctorType);
llvm::Function *fn =
cast<llvm::Function>(GetAddrOfCXXConstructor(ctor, ctorType, &fnInfo));
@ -218,11 +219,10 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
if (llvm::GlobalValue *existing = GetGlobalValue(name))
return existing;
if (!fnInfo) fnInfo = &getTypes().getFunctionInfo(ctor, ctorType);
if (!fnInfo)
fnInfo = &getTypes().arrangeCXXConstructorDeclaration(ctor, ctorType);
const FunctionProtoType *proto = ctor->getType()->castAs<FunctionProtoType>();
llvm::FunctionType *fnType =
getTypes().GetFunctionType(*fnInfo, proto->isVariadic());
llvm::FunctionType *fnType = getTypes().GetFunctionType(*fnInfo);
return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
/*ForVTable=*/false));
}
@ -260,7 +260,8 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor,
if (dtorType == Dtor_Base && !TryEmitBaseDestructorAsAlias(dtor))
return;
const CGFunctionInfo &fnInfo = getTypes().getFunctionInfo(dtor, dtorType);
const CGFunctionInfo &fnInfo =
getTypes().arrangeCXXDestructor(dtor, dtorType);
llvm::Function *fn =
cast<llvm::Function>(GetAddrOfCXXDestructor(dtor, dtorType, &fnInfo));
@ -282,11 +283,9 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor,
if (llvm::GlobalValue *existing = GetGlobalValue(name))
return existing;
if (!fnInfo) fnInfo = &getTypes().getFunctionInfo(dtor, dtorType);
llvm::FunctionType *fnType =
getTypes().GetFunctionType(*fnInfo, false);
if (!fnInfo) fnInfo = &getTypes().arrangeCXXDestructor(dtor, dtorType);
llvm::FunctionType *fnType = getTypes().GetFunctionType(*fnInfo);
return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD,
/*ForVTable=*/false));
}
@ -359,12 +358,10 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall(
// -O does that. But need to support -O0 as well.
if (MD->isVirtual() && Type != Dtor_Base) {
// Compute the function type we're calling.
const CGFunctionInfo *FInfo =
&CGM.getTypes().getFunctionInfo(cast<CXXDestructorDecl>(MD),
Dtor_Complete);
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
llvm::Type *Ty
= CGM.getTypes().GetFunctionType(*FInfo, FPT->isVariadic());
const CGFunctionInfo &FInfo =
CGM.getTypes().arrangeCXXDestructor(cast<CXXDestructorDecl>(MD),
Dtor_Complete);
llvm::Type *Ty = CGM.getTypes().GetFunctionType(FInfo);
llvm::Value *VTable = CGM.getVTables().GetAddrOfVTable(RD);
Ty = Ty->getPointerTo()->getPointerTo();

View File

@ -49,9 +49,8 @@ llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
MPT->getPointeeType()->getAs<FunctionProtoType>();
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
llvm::FunctionType *FTy =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
FPT->isVariadic());
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodType(RD, FPT));
return llvm::Constant::getNullValue(FTy->getPointerTo());
}

View File

@ -17,6 +17,7 @@
#include "ABIInfo.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
@ -66,29 +67,39 @@ static CanQualType GetReturnType(QualType RetTy) {
return RetTy->getCanonicalTypeUnqualified().getUnqualifiedType();
}
/// Arrange the argument and result information for a value of the
/// given unprototyped function type.
const CGFunctionInfo &
CodeGenTypes::getFunctionInfo(CanQual<FunctionNoProtoType> FTNP) {
return getFunctionInfo(FTNP->getResultType().getUnqualifiedType(),
SmallVector<CanQualType, 16>(),
FTNP->getExtInfo());
CodeGenTypes::arrangeFunctionType(CanQual<FunctionNoProtoType> FTNP) {
// When translating an unprototyped function type, always use a
// variadic type.
return arrangeFunctionType(FTNP->getResultType().getUnqualifiedType(),
ArrayRef<CanQualType>(),
FTNP->getExtInfo(),
RequiredArgs(0));
}
/// \param Args - contains any initial parameters besides those
/// in the formal type
static const CGFunctionInfo &getFunctionInfo(CodeGenTypes &CGT,
SmallVectorImpl<CanQualType> &ArgTys,
/// Arrange the argument and result information for a value of the
/// given function type, on top of any implicit parameters already
/// stored.
static const CGFunctionInfo &arrangeFunctionType(CodeGenTypes &CGT,
SmallVectorImpl<CanQualType> &argTypes,
CanQual<FunctionProtoType> FTP) {
RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, argTypes.size());
// FIXME: Kill copy.
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i));
CanQualType ResTy = FTP->getResultType().getUnqualifiedType();
return CGT.getFunctionInfo(ResTy, ArgTys, FTP->getExtInfo());
argTypes.push_back(FTP->getArgType(i));
CanQualType resultType = FTP->getResultType().getUnqualifiedType();
return CGT.arrangeFunctionType(resultType, argTypes,
FTP->getExtInfo(), required);
}
/// Arrange the argument and result information for a value of the
/// given function type.
const CGFunctionInfo &
CodeGenTypes::getFunctionInfo(CanQual<FunctionProtoType> FTP) {
SmallVector<CanQualType, 16> ArgTys;
return ::getFunctionInfo(*this, ArgTys, FTP);
CodeGenTypes::arrangeFunctionType(CanQual<FunctionProtoType> FTP) {
SmallVector<CanQualType, 16> argTypes;
return ::arrangeFunctionType(*this, argTypes, FTP);
}
static CallingConv getCallingConventionForDecl(const Decl *D) {
@ -111,82 +122,133 @@ static CallingConv getCallingConventionForDecl(const Decl *D) {
return CC_C;
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD,
const FunctionProtoType *FTP) {
SmallVector<CanQualType, 16> ArgTys;
/// Arrange the argument and result information for a call to an
/// unknown C++ non-static member function of the given abstract type.
/// The member function must be an ordinary function, i.e. not a
/// constructor or destructor.
const CGFunctionInfo &
CodeGenTypes::arrangeCXXMethodType(const CXXRecordDecl *RD,
const FunctionProtoType *FTP) {
SmallVector<CanQualType, 16> argTypes;
// Add the 'this' pointer.
ArgTys.push_back(GetThisType(Context, RD));
argTypes.push_back(GetThisType(Context, RD));
return ::getFunctionInfo(*this, ArgTys,
return ::arrangeFunctionType(*this, argTypes,
FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>());
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
SmallVector<CanQualType, 16> ArgTys;
/// Arrange the argument and result information for a declaration or
/// definition of the given C++ non-static member function. The
/// member function must be an ordinary function, i.e. not a
/// constructor or destructor.
const CGFunctionInfo &
CodeGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *MD) {
assert(!isa<CXXConstructorDecl>(MD) && "wrong method for contructors!");
assert(!isa<CXXDestructorDecl>(MD) && "wrong method for destructors!");
// Add the 'this' pointer unless this is a static method.
if (MD->isInstance())
ArgTys.push_back(GetThisType(Context, MD->getParent()));
CanQual<FunctionProtoType> prototype = GetFormalType(MD);
return ::getFunctionInfo(*this, ArgTys, GetFormalType(MD));
if (MD->isInstance()) {
// The abstract case is perfectly fine.
return arrangeCXXMethodType(MD->getParent(), prototype.getTypePtr());
}
return arrangeFunctionType(prototype);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D,
CXXCtorType Type) {
SmallVector<CanQualType, 16> ArgTys;
ArgTys.push_back(GetThisType(Context, D->getParent()));
CanQualType ResTy = Context.VoidTy;
/// Arrange the argument and result information for a declaration
/// or definition to the given constructor variant.
const CGFunctionInfo &
CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D,
CXXCtorType ctorKind) {
SmallVector<CanQualType, 16> argTypes;
argTypes.push_back(GetThisType(Context, D->getParent()));
CanQualType resultType = Context.VoidTy;
TheCXXABI.BuildConstructorSignature(D, Type, ResTy, ArgTys);
TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes);
CanQual<FunctionProtoType> FTP = GetFormalType(D);
RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, argTypes.size());
// Add the formal parameters.
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i));
argTypes.push_back(FTP->getArgType(i));
return getFunctionInfo(ResTy, ArgTys, FTP->getExtInfo());
return arrangeFunctionType(resultType, argTypes, FTP->getExtInfo(), required);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D,
CXXDtorType Type) {
SmallVector<CanQualType, 2> ArgTys;
ArgTys.push_back(GetThisType(Context, D->getParent()));
CanQualType ResTy = Context.VoidTy;
/// Arrange the argument and result information for a declaration,
/// definition, or call to the given destructor variant. It so
/// happens that all three cases produce the same information.
const CGFunctionInfo &
CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType dtorKind) {
SmallVector<CanQualType, 2> argTypes;
argTypes.push_back(GetThisType(Context, D->getParent()));
CanQualType resultType = Context.VoidTy;
TheCXXABI.BuildDestructorSignature(D, Type, ResTy, ArgTys);
TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes);
CanQual<FunctionProtoType> FTP = GetFormalType(D);
assert(FTP->getNumArgs() == 0 && "dtor with formal parameters");
return getFunctionInfo(ResTy, ArgTys, FTP->getExtInfo());
return arrangeFunctionType(resultType, argTypes, FTP->getExtInfo(),
RequiredArgs::All);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) {
/// Arrange the argument and result information for the declaration or
/// definition of the given function.
const CGFunctionInfo &
CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) {
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
if (MD->isInstance())
return getFunctionInfo(MD);
return arrangeCXXMethodDeclaration(MD);
CanQualType FTy = FD->getType()->getCanonicalTypeUnqualified();
assert(isa<FunctionType>(FTy));
if (isa<FunctionNoProtoType>(FTy))
return getFunctionInfo(FTy.getAs<FunctionNoProtoType>());
// When declaring a function without a prototype, always use a
// non-variadic type.
if (isa<FunctionNoProtoType>(FTy)) {
CanQual<FunctionNoProtoType> noProto = FTy.getAs<FunctionNoProtoType>();
return arrangeFunctionType(noProto->getResultType(),
ArrayRef<CanQualType>(),
noProto->getExtInfo(),
RequiredArgs::All);
}
assert(isa<FunctionProtoType>(FTy));
return getFunctionInfo(FTy.getAs<FunctionProtoType>());
return arrangeFunctionType(FTy.getAs<FunctionProtoType>());
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
SmallVector<CanQualType, 16> ArgTys;
ArgTys.push_back(Context.getCanonicalParamType(MD->getSelfDecl()->getType()));
ArgTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType()));
/// Arrange the argument and result information for the declaration or
/// definition of an Objective-C method.
const CGFunctionInfo &
CodeGenTypes::arrangeObjCMethodDeclaration(const ObjCMethodDecl *MD) {
// It happens that this is the same as a call with no optional
// arguments, except also using the formal 'self' type.
return arrangeObjCMessageSendSignature(MD, MD->getSelfDecl()->getType());
}
/// Arrange the argument and result information for the function type
/// through which to perform a send to the given Objective-C method,
/// using the given receiver type. The receiver type is not always
/// the 'self' type of the method or even an Objective-C pointer type.
/// This is *not* the right method for actually performing such a
/// message send, due to the possibility of optional arguments.
const CGFunctionInfo &
CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
QualType receiverType) {
SmallVector<CanQualType, 16> argTys;
argTys.push_back(Context.getCanonicalParamType(receiverType));
argTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType()));
// FIXME: Kill copy?
for (ObjCMethodDecl::param_const_iterator i = MD->param_begin(),
e = MD->param_end(); i != e; ++i) {
ArgTys.push_back(Context.getCanonicalParamType((*i)->getType()));
argTys.push_back(Context.getCanonicalParamType((*i)->getType()));
}
FunctionType::ExtInfo einfo;
@ -196,77 +258,114 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
MD->hasAttr<NSReturnsRetainedAttr>())
einfo = einfo.withProducesResult(true);
return getFunctionInfo(GetReturnType(MD->getResultType()), ArgTys, einfo);
RequiredArgs required =
(MD->isVariadic() ? RequiredArgs(argTys.size()) : RequiredArgs::All);
return arrangeFunctionType(GetReturnType(MD->getResultType()), argTys,
einfo, required);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) {
const CGFunctionInfo &
CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) {
// FIXME: Do we need to handle ObjCMethodDecl?
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
return getFunctionInfo(CD, GD.getCtorType());
return arrangeCXXConstructorDeclaration(CD, GD.getCtorType());
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD))
return getFunctionInfo(DD, GD.getDtorType());
return arrangeCXXDestructor(DD, GD.getDtorType());
return getFunctionInfo(FD);
return arrangeFunctionDeclaration(FD);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const CallArgList &Args,
const FunctionType::ExtInfo &Info) {
/// Figure out the rules for calling a function with the given formal
/// type using the given arguments. The arguments are necessary
/// because the function might be unprototyped, in which case it's
/// target-dependent in crazy ways.
const CGFunctionInfo &
CodeGenTypes::arrangeFunctionCall(const CallArgList &args,
const FunctionType *fnType) {
RequiredArgs required = RequiredArgs::All;
if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) {
if (proto->isVariadic())
required = RequiredArgs(proto->getNumArgs());
} else if (CGM.getTargetCodeGenInfo()
.isNoProtoCallVariadic(args, cast<FunctionNoProtoType>(fnType))) {
required = RequiredArgs(0);
}
return arrangeFunctionCall(fnType->getResultType(), args,
fnType->getExtInfo(), required);
}
const CGFunctionInfo &
CodeGenTypes::arrangeFunctionCall(QualType resultType,
const CallArgList &args,
const FunctionType::ExtInfo &info,
RequiredArgs required) {
// FIXME: Kill copy.
SmallVector<CanQualType, 16> ArgTys;
for (CallArgList::const_iterator i = Args.begin(), e = Args.end();
SmallVector<CanQualType, 16> argTypes;
for (CallArgList::const_iterator i = args.begin(), e = args.end();
i != e; ++i)
ArgTys.push_back(Context.getCanonicalParamType(i->Ty));
return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info);
argTypes.push_back(Context.getCanonicalParamType(i->Ty));
return arrangeFunctionType(GetReturnType(resultType), argTypes, info,
required);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const FunctionArgList &Args,
const FunctionType::ExtInfo &Info) {
const CGFunctionInfo &
CodeGenTypes::arrangeFunctionDeclaration(QualType resultType,
const FunctionArgList &args,
const FunctionType::ExtInfo &info,
bool isVariadic) {
// FIXME: Kill copy.
SmallVector<CanQualType, 16> ArgTys;
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
SmallVector<CanQualType, 16> argTypes;
for (FunctionArgList::const_iterator i = args.begin(), e = args.end();
i != e; ++i)
ArgTys.push_back(Context.getCanonicalParamType((*i)->getType()));
return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info);
argTypes.push_back(Context.getCanonicalParamType((*i)->getType()));
RequiredArgs required =
(isVariadic ? RequiredArgs(args.size()) : RequiredArgs::All);
return arrangeFunctionType(GetReturnType(resultType), argTypes, info,
required);
}
const CGFunctionInfo &CodeGenTypes::getNullaryFunctionInfo() {
SmallVector<CanQualType, 1> args;
return getFunctionInfo(getContext().VoidTy, args, FunctionType::ExtInfo());
const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() {
return arrangeFunctionType(getContext().VoidTy, ArrayRef<CanQualType>(),
FunctionType::ExtInfo(), RequiredArgs::All);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
const SmallVectorImpl<CanQualType> &ArgTys,
const FunctionType::ExtInfo &Info) {
/// 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::arrangeFunctionType(CanQualType resultType,
ArrayRef<CanQualType> argTypes,
const FunctionType::ExtInfo &info,
RequiredArgs required) {
#ifndef NDEBUG
for (SmallVectorImpl<CanQualType>::const_iterator
I = ArgTys.begin(), E = ArgTys.end(); I != E; ++I)
for (ArrayRef<CanQualType>::const_iterator
I = argTypes.begin(), E = argTypes.end(); I != E; ++I)
assert(I->isCanonicalAsParam());
#endif
unsigned CC = ClangCallConvToLLVMCallConv(Info.getCC());
unsigned CC = ClangCallConvToLLVMCallConv(info.getCC());
// Lookup or create unique function info.
llvm::FoldingSetNodeID ID;
CGFunctionInfo::Profile(ID, Info, ResTy, ArgTys.begin(), ArgTys.end());
CGFunctionInfo::Profile(ID, info, required, resultType, argTypes);
void *InsertPos = 0;
CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, InsertPos);
void *insertPos = 0;
CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, insertPos);
if (FI)
return *FI;
// Construct the function info.
FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getProducesResult(),
Info.getHasRegParm(), Info.getRegParm(), ResTy,
ArgTys.data(), ArgTys.size());
FunctionInfos.InsertNode(FI, InsertPos);
// Construct the function info. We co-allocate the ArgInfos.
FI = CGFunctionInfo::create(CC, info, resultType, argTypes, required);
FunctionInfos.InsertNode(FI, insertPos);
bool Inserted = FunctionsBeingProcessed.insert(FI); (void)Inserted;
assert(Inserted && "Recursively being processed?");
bool inserted = FunctionsBeingProcessed.insert(FI); (void)inserted;
assert(inserted && "Recursively being processed?");
// Compute ABI information.
getABIInfo().computeInfo(*FI);
@ -274,39 +373,42 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
// Loop over all of the computed argument and return value info. If any of
// them are direct or extend without a specified coerce type, specify the
// default now.
ABIArgInfo &RetInfo = FI->getReturnInfo();
if (RetInfo.canHaveCoerceToType() && RetInfo.getCoerceToType() == 0)
RetInfo.setCoerceToType(ConvertType(FI->getReturnType()));
ABIArgInfo &retInfo = FI->getReturnInfo();
if (retInfo.canHaveCoerceToType() && retInfo.getCoerceToType() == 0)
retInfo.setCoerceToType(ConvertType(FI->getReturnType()));
for (CGFunctionInfo::arg_iterator I = FI->arg_begin(), E = FI->arg_end();
I != E; ++I)
if (I->info.canHaveCoerceToType() && I->info.getCoerceToType() == 0)
I->info.setCoerceToType(ConvertType(I->type));
bool Erased = FunctionsBeingProcessed.erase(FI); (void)Erased;
assert(Erased && "Not in set?");
bool erased = FunctionsBeingProcessed.erase(FI); (void)erased;
assert(erased && "Not in set?");
return *FI;
}
CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
bool _NoReturn, bool returnsRetained,
bool _HasRegParm, unsigned _RegParm,
CanQualType ResTy,
const CanQualType *ArgTys,
unsigned NumArgTys)
: CallingConvention(_CallingConvention),
EffectiveCallingConvention(_CallingConvention),
NoReturn(_NoReturn), ReturnsRetained(returnsRetained),
HasRegParm(_HasRegParm), RegParm(_RegParm)
{
NumArgs = NumArgTys;
// FIXME: Coallocate with the CGFunctionInfo object.
Args = new ArgInfo[1 + NumArgTys];
Args[0].type = ResTy;
for (unsigned i = 0; i != NumArgTys; ++i)
Args[1 + i].type = ArgTys[i];
CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC,
const FunctionType::ExtInfo &info,
CanQualType resultType,
ArrayRef<CanQualType> argTypes,
RequiredArgs required) {
void *buffer = operator new(sizeof(CGFunctionInfo) +
sizeof(ArgInfo) * (argTypes.size() + 1));
CGFunctionInfo *FI = new(buffer) CGFunctionInfo();
FI->CallingConvention = llvmCC;
FI->EffectiveCallingConvention = llvmCC;
FI->ASTCallingConvention = info.getCC();
FI->NoReturn = info.getNoReturn();
FI->ReturnsRetained = info.getProducesResult();
FI->Required = required;
FI->HasRegParm = info.getHasRegParm();
FI->RegParm = info.getRegParm();
FI->NumArgs = argTypes.size();
FI->getArgsBuffer()[0].type = resultType;
for (unsigned i = 0, e = argTypes.size(); i != e; ++i)
FI->getArgsBuffer()[i + 1].type = argTypes[i];
return FI;
}
/***/
@ -623,19 +725,12 @@ bool CodeGenModule::ReturnTypeUsesFP2Ret(QualType ResultType) {
}
llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
const CGFunctionInfo &FI = getFunctionInfo(GD);
// For definition purposes, don't consider a K&R function variadic.
bool Variadic = false;
if (const FunctionProtoType *FPT =
cast<FunctionDecl>(GD.getDecl())->getType()->getAs<FunctionProtoType>())
Variadic = FPT->isVariadic();
return GetFunctionType(FI, Variadic);
const CGFunctionInfo &FI = arrangeGlobalDeclaration(GD);
return GetFunctionType(FI);
}
llvm::FunctionType *
CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
bool Inserted = FunctionsBeingProcessed.insert(&FI); (void)Inserted;
assert(Inserted && "Recursively being processed?");
@ -711,7 +806,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic) {
bool Erased = FunctionsBeingProcessed.erase(&FI); (void)Erased;
assert(Erased && "Not in set?");
return llvm::FunctionType::get(resultType, argTypes, isVariadic);
return llvm::FunctionType::get(resultType, argTypes, FI.isVariadic());
}
llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
@ -723,10 +818,10 @@ llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
const CGFunctionInfo *Info;
if (isa<CXXDestructorDecl>(MD))
Info = &getFunctionInfo(cast<CXXDestructorDecl>(MD), GD.getDtorType());
Info = &arrangeCXXDestructor(cast<CXXDestructorDecl>(MD), GD.getDtorType());
else
Info = &getFunctionInfo(MD);
return GetFunctionType(*Info, FPT->isVariadic());
Info = &arrangeCXXMethodDeclaration(MD);
return GetFunctionType(*Info);
}
void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,

View File

@ -98,6 +98,55 @@ namespace CodeGen {
SmallVector<Writeback, 1> Writebacks;
};
/// A class for recording the number of arguments that a function
/// signature requires.
class RequiredArgs {
/// The number of required arguments, or ~0 if the signature does
/// not permit optional arguments.
unsigned NumRequired;
public:
enum All_t { All };
RequiredArgs(All_t _) : NumRequired(~0U) {}
explicit RequiredArgs(unsigned n) : NumRequired(n) {
assert(n != ~0U);
}
/// Compute the arguments required by the given formal prototype,
/// given that there may be some additional, non-formal arguments
/// in play.
static RequiredArgs forPrototypePlus(const FunctionProtoType *prototype,
unsigned additional) {
if (!prototype->isVariadic()) return All;
return RequiredArgs(prototype->getNumArgs() + additional);
}
static RequiredArgs forPrototype(const FunctionProtoType *prototype) {
return forPrototypePlus(prototype, 0);
}
static RequiredArgs forPrototype(CanQual<FunctionProtoType> prototype) {
return forPrototype(prototype.getTypePtr());
}
static RequiredArgs forPrototypePlus(CanQual<FunctionProtoType> prototype,
unsigned additional) {
return forPrototypePlus(prototype.getTypePtr(), additional);
}
bool allowsOptionalArgs() const { return NumRequired != ~0U; }
bool getNumRequiredArgs() const {
assert(allowsOptionalArgs());
return NumRequired;
}
unsigned getOpaqueData() const { return NumRequired; }
static RequiredArgs getFromOpaqueData(unsigned value) {
if (value == ~0U) return All;
return RequiredArgs(value);
}
};
/// FunctionArgList - Type for representing both the decl and type
/// of parameters to a function. The decl must be either a
/// ParmVarDecl or ImplicitParamDecl.
@ -114,50 +163,71 @@ namespace CodeGen {
/// The LLVM::CallingConv to use for this function (as specified by the
/// user).
unsigned CallingConvention;
unsigned CallingConvention : 8;
/// The LLVM::CallingConv to actually use for this function, which may
/// depend on the ABI.
unsigned EffectiveCallingConvention;
unsigned EffectiveCallingConvention : 8;
/// The clang::CallingConv that this was originally created with.
unsigned ASTCallingConvention : 8;
/// Whether this function is noreturn.
bool NoReturn;
unsigned NoReturn : 1;
/// Whether this function is returns-retained.
bool ReturnsRetained;
unsigned NumArgs;
ArgInfo *Args;
unsigned ReturnsRetained : 1;
/// How many arguments to pass inreg.
bool HasRegParm;
unsigned RegParm;
unsigned HasRegParm : 1;
unsigned RegParm : 4;
RequiredArgs Required;
unsigned NumArgs;
ArgInfo *getArgsBuffer() {
return reinterpret_cast<ArgInfo*>(this+1);
}
const ArgInfo *getArgsBuffer() const {
return reinterpret_cast<const ArgInfo*>(this + 1);
}
CGFunctionInfo() : Required(RequiredArgs::All) {}
public:
static CGFunctionInfo *create(unsigned llvmCC,
const FunctionType::ExtInfo &extInfo,
CanQualType resultType,
ArrayRef<CanQualType> argTypes,
RequiredArgs required);
typedef const ArgInfo *const_arg_iterator;
typedef ArgInfo *arg_iterator;
CGFunctionInfo(unsigned CallingConvention, bool NoReturn,
bool ReturnsRetained, bool HasRegParm, unsigned RegParm,
CanQualType ResTy,
const CanQualType *ArgTys, unsigned NumArgTys);
~CGFunctionInfo() { delete[] Args; }
const_arg_iterator arg_begin() const { return Args + 1; }
const_arg_iterator arg_end() const { return Args + 1 + NumArgs; }
arg_iterator arg_begin() { return Args + 1; }
arg_iterator arg_end() { return Args + 1 + NumArgs; }
const_arg_iterator arg_begin() const { return getArgsBuffer() + 1; }
const_arg_iterator arg_end() const { return getArgsBuffer() + 1 + NumArgs; }
arg_iterator arg_begin() { return getArgsBuffer() + 1; }
arg_iterator arg_end() { return getArgsBuffer() + 1 + NumArgs; }
unsigned arg_size() const { return NumArgs; }
bool isVariadic() const { return Required.allowsOptionalArgs(); }
RequiredArgs getRequiredArgs() const { return Required; }
bool isNoReturn() const { return NoReturn; }
/// In ARR, whether this function retains its return value. This
/// In ARC, whether this function retains its return value. This
/// is not always reliable for call sites.
bool isReturnsRetained() const { return ReturnsRetained; }
/// getCallingConvention - Return the user specified calling
/// getASTCallingConvention() - Return the AST-specified calling
/// convention.
CallingConv getASTCallingConvention() const {
return CallingConv(ASTCallingConvention);
}
/// getCallingConvention - Return the user specified calling
/// convention, which has been translated into an LLVM CC.
unsigned getCallingConvention() const { return CallingConvention; }
/// getEffectiveCallingConvention - Return the actual calling convention to
@ -172,36 +242,44 @@ namespace CodeGen {
bool getHasRegParm() const { return HasRegParm; }
unsigned getRegParm() const { return RegParm; }
CanQualType getReturnType() const { return Args[0].type; }
FunctionType::ExtInfo getExtInfo() const {
return FunctionType::ExtInfo(isNoReturn(),
getHasRegParm(), getRegParm(),
getASTCallingConvention(),
isReturnsRetained());
}
ABIArgInfo &getReturnInfo() { return Args[0].info; }
const ABIArgInfo &getReturnInfo() const { return Args[0].info; }
CanQualType getReturnType() const { return getArgsBuffer()[0].type; }
ABIArgInfo &getReturnInfo() { return getArgsBuffer()[0].info; }
const ABIArgInfo &getReturnInfo() const { return getArgsBuffer()[0].info; }
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddInteger(getCallingConvention());
ID.AddInteger(getASTCallingConvention());
ID.AddBoolean(NoReturn);
ID.AddBoolean(ReturnsRetained);
ID.AddBoolean(HasRegParm);
ID.AddInteger(RegParm);
ID.AddInteger(Required.getOpaqueData());
getReturnType().Profile(ID);
for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it)
it->type.Profile(ID);
}
template<class Iterator>
static void Profile(llvm::FoldingSetNodeID &ID,
const FunctionType::ExtInfo &Info,
CanQualType ResTy,
Iterator begin,
Iterator end) {
ID.AddInteger(Info.getCC());
ID.AddBoolean(Info.getNoReturn());
ID.AddBoolean(Info.getProducesResult());
ID.AddBoolean(Info.getHasRegParm());
ID.AddInteger(Info.getRegParm());
ResTy.Profile(ID);
for (; begin != end; ++begin) {
CanQualType T = *begin; // force iterator to be over canonical types
T.Profile(ID);
const FunctionType::ExtInfo &info,
RequiredArgs required,
CanQualType resultType,
ArrayRef<CanQualType> argTypes) {
ID.AddInteger(info.getCC());
ID.AddBoolean(info.getNoReturn());
ID.AddBoolean(info.getProducesResult());
ID.AddBoolean(info.getHasRegParm());
ID.AddInteger(info.getRegParm());
ID.AddInteger(required.getOpaqueData());
resultType.Profile(ID);
for (ArrayRef<CanQualType>::iterator
i = argTypes.begin(), e = argTypes.end(); i != e; ++i) {
i->Profile(ID);
}
}
};

View File

@ -1289,7 +1289,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
EmitCallArg(Args, *Arg, ArgType);
}
EmitCall(CGM.getTypes().getFunctionInfo(Args, FPT), Callee,
EmitCall(CGM.getTypes().arrangeFunctionCall(Args, FPT), Callee,
ReturnValueSlot(), Args, D);
}
@ -1325,7 +1325,7 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
EmitDelegateCallArg(DelegateArgs, param);
}
EmitCall(CGM.getTypes().getFunctionInfo(Ctor, CtorType),
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
CGM.GetAddrOfCXXConstructor(Ctor, CtorType),
ReturnValueSlot(), DelegateArgs, Ctor);
}
@ -1710,15 +1710,14 @@ llvm::Value *
CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E,
const CXXMethodDecl *MD,
llvm::Value *This) {
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
FPT->isVariadic());
llvm::FunctionType *fnType =
CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodDeclaration(MD));
if (UseVirtualCall(getContext(), E, MD))
return BuildVirtualCall(MD, This, Ty);
return BuildVirtualCall(MD, This, fnType);
return CGM.GetAddrOfFunction(MD, Ty);
return CGM.GetAddrOfFunction(MD, fnType);
}
void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) {
@ -1750,9 +1749,10 @@ void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
// Get the address of the call operator.
GlobalDecl GD(CallOperator);
const CGFunctionInfo &CalleeFnInfo = CGM.getTypes().getFunctionInfo(GD);
llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CalleeFnInfo, FPT->isVariadic());
const CGFunctionInfo &CalleeFnInfo =
CGM.getTypes().arrangeFunctionCall(ResultType, CallArgs, FPT->getExtInfo(),
RequiredArgs::forPrototypePlus(FPT, 1));
llvm::Type *Ty = CGM.getTypes().GetFunctionType(CalleeFnInfo);
llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty);
// Determine whether we have a return value slot to use.

View File

@ -1184,7 +1184,7 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
llvm::Constant *F = CGM.GetAddrOfFunction(FD);
assert(F && "Could not find function!");
const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD);
const CGFunctionInfo &Info = CGM.getTypes().arrangeFunctionDeclaration(FD);
EHStack.pushCleanup<CallCleanupFunction>(NormalAndEHCleanup, F, &Info, &D);
}

View File

@ -277,7 +277,7 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
llvm::GlobalVariable *Addr,
bool PerformInit) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().getNullaryFunctionInfo(),
getTypes().arrangeNullaryFunction(),
FunctionArgList(), SourceLocation());
// Use guarded initialization if the global variable is weak. This
@ -297,7 +297,7 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
llvm::Constant **Decls,
unsigned NumDecls) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().getNullaryFunctionInfo(),
getTypes().arrangeNullaryFunction(),
FunctionArgList(), SourceLocation());
RunCleanupsScope Scope(*this);
@ -322,7 +322,7 @@ void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> >
&DtorsAndObjects) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
getTypes().getNullaryFunctionInfo(),
getTypes().arrangeNullaryFunction(),
FunctionArgList(), SourceLocation());
// Emit the dtors, in reverse order from construction.
@ -350,9 +350,10 @@ CodeGenFunction::generateDestroyHelper(llvm::Constant *addr,
args.push_back(&dst);
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(getContext().VoidTy, args,
FunctionType::ExtInfo());
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
CGM.getTypes().arrangeFunctionDeclaration(getContext().VoidTy, args,
FunctionType::ExtInfo(),
/*variadic*/ false);
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *fn =
CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor");

View File

@ -2454,7 +2454,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
CallArgList Args;
EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd);
const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(Args, FnType);
const CGFunctionInfo &FnInfo =
CGM.getTypes().arrangeFunctionCall(Args, FnType);
// C99 6.5.2.2p6:
// If the expression that denotes the called function has a type
@ -2473,11 +2474,8 @@ 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) &&
!getTargetHooks().isNoProtoCallVariadic(FnInfo)) {
assert(cast<llvm::FunctionType>(Callee->getType()->getContainedType(0))
->isVarArg());
llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo, false);
if (isa<FunctionNoProtoType>(FnType) && !FnInfo.isVariadic()) {
llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo);
CalleeTy = CalleeTy->getPointerTo();
Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast");
}
@ -2678,7 +2676,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
getContext().getSizeType());
const CGFunctionInfo &FuncInfo =
CGM.getTypes().getFunctionInfo(RetTy, Args, FunctionType::ExtInfo());
CGM.getTypes().arrangeFunctionCall(RetTy, Args, FunctionType::ExtInfo(),
/*variadic*/ false);
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo, false);
llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);

View File

@ -33,8 +33,6 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
assert(MD->isInstance() &&
"Trying to emit a member call expr on a static method!");
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
CallArgList Args;
// Push the this ptr.
@ -45,13 +43,16 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
QualType T = getContext().getPointerType(getContext().VoidPtrTy);
Args.add(RValue::get(VTT), T);
}
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, Args.size());
// And the rest of the call args
// And the rest of the call args.
EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
QualType ResultType = FPT->getResultType();
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
FPT->getExtInfo()),
return EmitCall(CGM.getTypes().arrangeFunctionCall(FPT->getResultType(), Args,
FPT->getExtInfo(),
required),
Callee, ReturnValue, Args, MD);
}
@ -229,17 +230,16 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
// Compute the function type we're calling.
const CGFunctionInfo *FInfo = 0;
if (isa<CXXDestructorDecl>(MD))
FInfo = &CGM.getTypes().getFunctionInfo(cast<CXXDestructorDecl>(MD),
Dtor_Complete);
FInfo = &CGM.getTypes().arrangeCXXDestructor(cast<CXXDestructorDecl>(MD),
Dtor_Complete);
else if (isa<CXXConstructorDecl>(MD))
FInfo = &CGM.getTypes().getFunctionInfo(cast<CXXConstructorDecl>(MD),
Ctor_Complete);
FInfo = &CGM.getTypes().arrangeCXXConstructorDeclaration(
cast<CXXConstructorDecl>(MD),
Ctor_Complete);
else
FInfo = &CGM.getTypes().getFunctionInfo(MD);
FInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(MD);
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
llvm::Type *Ty
= CGM.getTypes().GetFunctionType(*FInfo, FPT->isVariadic());
llvm::Type *Ty = CGM.getTypes().GetFunctionType(*FInfo);
// C++ [class.virtual]p12:
// Explicit qualification with the scope operator (5.1) suppresses the
@ -322,7 +322,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
// And the rest of the call args
EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
return EmitCall(CGM.getTypes().getFunctionInfo(Args, FPT), Callee,
return EmitCall(CGM.getTypes().arrangeFunctionCall(Args, FPT), Callee,
ReturnValue, Args);
}
@ -945,7 +945,7 @@ namespace {
DeleteArgs.add(getPlacementArgs()[I], *AI++);
// Call 'operator delete'.
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(DeleteArgs, FPT),
CGF.EmitCall(CGF.CGM.getTypes().arrangeFunctionCall(DeleteArgs, FPT),
CGF.CGM.GetAddrOfFunction(OperatorDelete),
ReturnValueSlot(), DeleteArgs, OperatorDelete);
}
@ -1006,7 +1006,7 @@ namespace {
}
// Call 'operator delete'.
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(DeleteArgs, FPT),
CGF.EmitCall(CGF.CGM.getTypes().arrangeFunctionCall(DeleteArgs, FPT),
CGF.CGM.GetAddrOfFunction(OperatorDelete),
ReturnValueSlot(), DeleteArgs, OperatorDelete);
}
@ -1113,7 +1113,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// TODO: kill any unnecessary computations done for the size
// argument.
} else {
RV = EmitCall(CGM.getTypes().getFunctionInfo(allocatorArgs, allocatorType),
RV = EmitCall(CGM.getTypes().arrangeFunctionCall(allocatorArgs,
allocatorType),
CGM.GetAddrOfFunction(allocator), ReturnValueSlot(),
allocatorArgs, allocator);
}
@ -1236,7 +1237,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
DeleteArgs.add(RValue::get(Size), SizeTy);
// Emit the call to delete.
EmitCall(CGM.getTypes().getFunctionInfo(DeleteArgs, DeleteFTy),
EmitCall(CGM.getTypes().arrangeFunctionCall(DeleteArgs, DeleteFTy),
CGM.GetAddrOfFunction(DeleteFD), ReturnValueSlot(),
DeleteArgs, DeleteFD);
}
@ -1283,9 +1284,8 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
}
llvm::Type *Ty =
CGF.getTypes().GetFunctionType(CGF.getTypes().getFunctionInfo(Dtor,
Dtor_Complete),
/*isVariadic=*/false);
CGF.getTypes().GetFunctionType(
CGF.getTypes().arrangeCXXDestructor(Dtor, Dtor_Complete));
llvm::Value *Callee
= CGF.BuildVirtualCall(Dtor,
@ -1393,7 +1393,7 @@ namespace {
}
// Emit the call to delete.
CGF.EmitCall(CGF.getTypes().getFunctionInfo(Args, DeleteFTy),
CGF.EmitCall(CGF.getTypes().arrangeFunctionCall(Args, DeleteFTy),
CGF.CGM.GetAddrOfFunction(OperatorDelete),
ReturnValueSlot(), Args, OperatorDelete);
}

View File

@ -307,7 +307,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD);
const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(OMD);
const CGFunctionInfo &FI = CGM.getTypes().arrangeObjCMethodDeclaration(OMD);
CGM.SetInternalFunctionAttributes(OMD, Fn, FI);
args.push_back(OMD->getSelfDecl());
@ -369,8 +369,9 @@ static void emitStructGetterCall(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
args.add(RValue::get(CGF.Builder.getInt1(hasStrong)), Context.BoolTy);
llvm::Value *fn = CGF.CGM.getObjCRuntime().GetGetStructFunction();
CGF.EmitCall(CGF.getTypes().getFunctionInfo(Context.VoidTy, args,
FunctionType::ExtInfo()),
CGF.EmitCall(CGF.getTypes().arrangeFunctionCall(Context.VoidTy, args,
FunctionType::ExtInfo(),
RequiredArgs::All),
fn, ReturnValueSlot(), args);
}
@ -624,8 +625,9 @@ static void emitCPPObjectAtomicGetterCall(CodeGenFunction &CGF,
llvm::Value *copyCppAtomicObjectFn =
CGF.CGM.getObjCRuntime().GetCppAtomicObjectFunction();
CGF.EmitCall(CGF.getTypes().getFunctionInfo(CGF.getContext().VoidTy, args,
FunctionType::ExtInfo()),
CGF.EmitCall(CGF.getTypes().arrangeFunctionCall(CGF.getContext().VoidTy, args,
FunctionType::ExtInfo(),
RequiredArgs::All),
copyCppAtomicObjectFn, ReturnValueSlot(), args);
}
@ -710,8 +712,9 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
// FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function.
RValue RV = EmitCall(getTypes().getFunctionInfo(propType, args,
FunctionType::ExtInfo()),
RValue RV = EmitCall(getTypes().arrangeFunctionCall(propType, args,
FunctionType::ExtInfo(),
RequiredArgs::All),
getPropertyFn, ReturnValueSlot(), args);
// We need to fix the type here. Ivars with copy & retain are
@ -811,8 +814,9 @@ static void emitStructSetterCall(CodeGenFunction &CGF, ObjCMethodDecl *OMD,
args.add(RValue::get(CGF.Builder.getFalse()), CGF.getContext().BoolTy);
llvm::Value *copyStructFn = CGF.CGM.getObjCRuntime().GetSetStructFunction();
CGF.EmitCall(CGF.getTypes().getFunctionInfo(CGF.getContext().VoidTy, args,
FunctionType::ExtInfo()),
CGF.EmitCall(CGF.getTypes().arrangeFunctionCall(CGF.getContext().VoidTy, args,
FunctionType::ExtInfo(),
RequiredArgs::All),
copyStructFn, ReturnValueSlot(), args);
}
@ -847,8 +851,9 @@ static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF,
llvm::Value *copyCppAtomicObjectFn =
CGF.CGM.getObjCRuntime().GetCppAtomicObjectFunction();
CGF.EmitCall(CGF.getTypes().getFunctionInfo(CGF.getContext().VoidTy, args,
FunctionType::ExtInfo()),
CGF.EmitCall(CGF.getTypes().arrangeFunctionCall(CGF.getContext().VoidTy, args,
FunctionType::ExtInfo(),
RequiredArgs::All),
copyCppAtomicObjectFn, ReturnValueSlot(), args);
@ -961,8 +966,9 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
getContext().BoolTy);
// FIXME: We shouldn't need to get the function info here, the runtime
// already should have computed it to build the function.
EmitCall(getTypes().getFunctionInfo(getContext().VoidTy, args,
FunctionType::ExtInfo()),
EmitCall(getTypes().arrangeFunctionCall(getContext().VoidTy, args,
FunctionType::ExtInfo(),
RequiredArgs::All),
setPropertyFn, ReturnValueSlot(), args);
return;
}
@ -1321,8 +1327,9 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
Args2.add(RValue::get(V), getContext().getObjCIdType());
// FIXME: We shouldn't need to get the function info here, the runtime already
// should have computed it to build the function.
EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2,
FunctionType::ExtInfo()),
EmitCall(CGM.getTypes().arrangeFunctionCall(getContext().VoidTy, Args2,
FunctionType::ExtInfo(),
RequiredArgs::All),
EnumerationMutationFn, ReturnValueSlot(), Args2);
// Otherwise, or if the mutation function returns, just continue.
@ -2556,7 +2563,7 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
// We just use an inline assembly.
llvm::FunctionType *extenderType
= llvm::FunctionType::get(VoidTy, VoidPtrTy, /*variadic*/ false);
= llvm::FunctionType::get(VoidTy, VoidPtrTy, RequiredArgs::All);
llvm::Value *extender
= llvm::InlineAsm::get(extenderType,
/* assembly */ "",
@ -2614,9 +2621,11 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
args.push_back(&srcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(C.VoidTy, args, FunctionType::ExtInfo());
CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
FunctionType::ExtInfo(),
RequiredArgs::All);
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
@ -2702,9 +2711,11 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
args.push_back(&srcDecl);
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(C.VoidTy, args, FunctionType::ExtInfo());
CGM.getTypes().arrangeFunctionDeclaration(C.VoidTy, args,
FunctionType::ExtInfo(),
RequiredArgs::All);
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,

View File

@ -103,8 +103,6 @@ class LazyRuntimeFunction {
/// GNUstep).
class CGObjCGNU : public CGObjCRuntime {
protected:
/// The module that is using this class
CodeGenModule &CGM;
/// The LLVM module into which output is inserted
llvm::Module &TheModule;
/// strut objc_super. Used for sending messages to super. This structure
@ -688,9 +686,9 @@ static std::string SymbolNameForMethod(const StringRef &ClassName,
CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
unsigned protocolClassVersion)
: CGM(cgm), TheModule(CGM.getModule()), VMContext(cgm.getLLVMContext()),
ClassPtrAlias(0), MetaClassPtrAlias(0), RuntimeVersion(runtimeABIVersion),
ProtocolVersion(protocolClassVersion) {
: CGObjCRuntime(cgm), TheModule(CGM.getModule()),
VMContext(cgm.getLLVMContext()), ClassPtrAlias(0), MetaClassPtrAlias(0),
RuntimeVersion(runtimeABIVersion), ProtocolVersion(protocolClassVersion) {
msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
@ -1037,9 +1035,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
ActualArgs.addFrom(CallArgs);
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
FunctionType::ExtInfo());
MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
llvm::Value *ReceiverClass = 0;
if (isCategoryImpl) {
@ -1092,12 +1088,10 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1));
ObjCSuper = EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy);
llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
// Get the IMP
llvm::Value *imp = LookupIMPSuper(CGF, ObjCSuper, cmd);
imp = EnforceType(Builder, imp, llvm::PointerType::getUnqual(impType));
imp = EnforceType(Builder, imp, MSI.MessengerType);
llvm::Value *impMD[] = {
llvm::MDString::get(VMContext, Sel.getAsString()),
@ -1107,8 +1101,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
llvm::Instruction *call;
RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs,
0, &call);
RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs, 0, &call);
call->setMetadata(msgSendMDKind, node);
return msgRet;
}
@ -1181,13 +1174,13 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
};
llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD);
CodeGenTypes &Types = CGM.getTypes();
CallArgList ActualArgs;
ActualArgs.add(RValue::get(Receiver), ASTIdTy);
ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
ActualArgs.addFrom(CallArgs);
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
FunctionType::ExtInfo());
MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
// Get the IMP to call
llvm::Value *imp;
@ -1203,7 +1196,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
if (CGM.ReturnTypeUsesFPRet(ResultType)) {
imp = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true),
"objc_msgSend_fpret");
} else if (CGM.ReturnTypeUsesSRet(FnInfo)) {
} else if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) {
// The actual types here don't matter - we're going to bitcast the
// function anyway
imp = CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true),
@ -1217,12 +1210,10 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
// Reset the receiver in case the lookup modified it
ActualArgs[0] = CallArg(RValue::get(Receiver), ASTIdTy, false);
llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
imp = EnforceType(Builder, imp, llvm::PointerType::getUnqual(impType));
imp = EnforceType(Builder, imp, MSI.MessengerType);
llvm::Instruction *call;
RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs,
RValue msgRet = CGF.EmitCall(MSI.CallInfo, imp, Return, ActualArgs,
0, &call);
call->setMetadata(msgSendMDKind, node);
@ -2418,7 +2409,7 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
CodeGenTypes &Types = CGM.getTypes();
llvm::FunctionType *MethodTy =
Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic());
Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName,
MethodName, isClassMethod);

View File

@ -241,9 +241,9 @@ public:
Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified());
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(IdType, Params,
FunctionType::ExtInfo()),
false);
Types.GetFunctionType(Types.arrangeFunctionType(IdType, Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
}
@ -261,9 +261,9 @@ public:
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
FunctionType::ExtInfo()),
false);
Types.GetFunctionType(Types.arrangeFunctionType(Ctx.VoidTy, Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
}
@ -279,9 +279,9 @@ public:
Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy);
llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
FunctionType::ExtInfo()),
false);
Types.GetFunctionType(Types.arrangeFunctionType(Ctx.VoidTy, Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct");
}
@ -298,9 +298,9 @@ public:
Params.push_back(Ctx.VoidPtrTy);
Params.push_back(Ctx.VoidPtrTy);
llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
FunctionType::ExtInfo()),
false);
Types.GetFunctionType(Types.arrangeFunctionType(Ctx.VoidTy, Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_copyCppObjectAtomic");
}
@ -311,9 +311,9 @@ public:
SmallVector<CanQualType,1> Params;
Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType()));
llvm::FunctionType *FTy =
Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params,
FunctionType::ExtInfo()),
false);
Types.GetFunctionType(Types.arrangeFunctionType(Ctx.VoidTy, Params,
FunctionType::ExtInfo(),
RequiredArgs::All));
return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
}
@ -719,7 +719,6 @@ public:
};
protected:
CodeGen::CodeGenModule &CGM;
llvm::LLVMContext &VMContext;
// FIXME! May not be needing this after all.
unsigned ObjCABI;
@ -904,7 +903,7 @@ protected:
public:
CGObjCCommonMac(CodeGen::CodeGenModule &cgm) :
CGM(cgm), VMContext(cgm.getLLVMContext()) { }
CGObjCRuntime(cgm), VMContext(cgm.getLLVMContext()) { }
virtual llvm::Constant *GenerateConstantString(const StringLiteral *SL);
@ -1675,11 +1674,8 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType());
ActualArgs.addFrom(CallArgs);
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
FunctionType::ExtInfo());
llvm::FunctionType *FTy =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
// If we're calling a method, use the formal signature.
MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
if (Method)
assert(CGM.getContext().getCanonicalType(Method->getResultType()) ==
@ -1689,7 +1685,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
NullReturnState nullReturn;
llvm::Constant *Fn = NULL;
if (CGM.ReturnTypeUsesSRet(FnInfo)) {
if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) {
if (!IsSuper) nullReturn.init(CGF, Arg0);
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
@ -1717,8 +1713,8 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
}
}
Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy));
RValue rvalue = CGF.EmitCall(FnInfo, Fn, Return, ActualArgs);
Fn = llvm::ConstantExpr::getBitCast(Fn, MSI.MessengerType);
RValue rvalue = CGF.EmitCall(MSI.CallInfo, Fn, Return, ActualArgs);
return nullReturn.complete(CGF, rvalue, ResultType, CallArgs,
requiresnullCheck ? Method : 0);
}
@ -2683,7 +2679,7 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
CodeGenTypes &Types = CGM.getTypes();
llvm::FunctionType *MethodTy =
Types.GetFunctionType(Types.getFunctionInfo(OMD), OMD->isVariadic());
Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD));
llvm::Function *Method =
llvm::Function::Create(MethodTy,
llvm::GlobalValue::InternalLinkage,
@ -5766,9 +5762,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
args.insert(args.end(), formalArgs.begin(), formalArgs.end());
const CGFunctionInfo &fnInfo =
CGM.getTypes().getFunctionInfo(resultType, args,
FunctionType::ExtInfo());
MessageSendInfo MSI = getMessageSendInfo(method, resultType, args);
NullReturnState nullReturn;
@ -5781,7 +5775,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
// FIXME: don't use this for that.
llvm::Constant *fn = 0;
std::string messageRefName("\01l_");
if (CGM.ReturnTypeUsesSRet(fnInfo)) {
if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) {
if (isSuper) {
fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
messageRefName += "objc_msgSendSuper2_stret_fixup";
@ -5849,13 +5843,9 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
llvm::Value *callee = CGF.Builder.CreateStructGEP(mref, 0);
callee = CGF.Builder.CreateLoad(callee, "msgSend_fn");
bool variadic = method ? method->isVariadic() : false;
llvm::FunctionType *fnType =
CGF.getTypes().GetFunctionType(fnInfo, variadic);
callee = CGF.Builder.CreateBitCast(callee,
llvm::PointerType::getUnqual(fnType));
callee = CGF.Builder.CreateBitCast(callee, MSI.MessengerType);
RValue result = CGF.EmitCall(fnInfo, callee, returnSlot, args);
RValue result = CGF.EmitCall(MSI.CallInfo, callee, returnSlot, args);
return nullReturn.complete(CGF, result, resultType, formalArgs,
requiresnullCheck ? method : 0);
}

View File

@ -327,3 +327,48 @@ void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF,
// Emit the body of the statement.
CGF.EmitStmt(S.getSynchBody());
}
/// Compute the pointer-to-function type to which a message send
/// should be casted in order to correctly call the given method
/// with the given arguments.
///
/// \param method - may be null
/// \param resultType - the result type to use if there's no method
/// \param argInfo - the actual arguments, including implicit ones
CGObjCRuntime::MessageSendInfo
CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method,
QualType resultType,
CallArgList &callArgs) {
// If there's a method, use information from that.
if (method) {
const CGFunctionInfo &signature =
CGM.getTypes().arrangeObjCMessageSendSignature(method, callArgs[0].Ty);
llvm::PointerType *signatureType =
CGM.getTypes().GetFunctionType(signature)->getPointerTo();
// If that's not variadic, there's no need to recompute the ABI
// arrangement.
if (!signature.isVariadic())
return MessageSendInfo(signature, signatureType);
// Otherwise, there is.
FunctionType::ExtInfo einfo = signature.getExtInfo();
const CGFunctionInfo &argsInfo =
CGM.getTypes().arrangeFunctionCall(resultType, callArgs, einfo,
signature.getRequiredArgs());
return MessageSendInfo(argsInfo, signatureType);
}
// There's no method; just use a default CC.
const CGFunctionInfo &argsInfo =
CGM.getTypes().arrangeFunctionCall(resultType, callArgs,
FunctionType::ExtInfo(),
RequiredArgs::All);
// Derive the signature to call from that.
llvm::PointerType *signatureType =
CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo();
return MessageSendInfo(argsInfo, signatureType);
}

View File

@ -63,6 +63,9 @@ namespace CodeGen {
/// Implements runtime-specific code generation functions.
class CGObjCRuntime {
protected:
CodeGen::CodeGenModule &CGM;
CGObjCRuntime(CodeGen::CodeGenModule &CGM) : CGM(CGM) {}
// Utility functions for unified ivar access. These need to
// eventually be folded into other places (the structure layout
// code).
@ -255,6 +258,19 @@ public:
virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
const CodeGen::CGBlockInfo &blockInfo) = 0;
virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) = 0;
struct MessageSendInfo {
const CGFunctionInfo &CallInfo;
llvm::PointerType *MessengerType;
MessageSendInfo(const CGFunctionInfo &callInfo,
llvm::PointerType *messengerType)
: CallInfo(callInfo), MessengerType(messengerType) {}
};
MessageSendInfo getMessageSendInfo(const ObjCMethodDecl *method,
QualType resultType,
CallArgList &callArgs);
};
/// Creates an instance of an Objective-C runtime class.

View File

@ -242,8 +242,8 @@ void CodeGenFunction::GenerateVarArgsThunk(
QualType ResultType = FPT->getResultType();
// Get the original function
llvm::Type *Ty =
CGM.getTypes().GetFunctionType(FnInfo, /*IsVariadic*/true);
assert(FnInfo.isVariadic());
llvm::Type *Ty = CGM.getTypes().GetFunctionType(FnInfo);
llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
llvm::Function *BaseFn = cast<llvm::Function>(Callee);
@ -351,13 +351,13 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
// Get our callee.
llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(GD),
FPT->isVariadic());
CGM.getTypes().GetFunctionType(CGM.getTypes().arrangeGlobalDeclaration(GD));
llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
#ifndef NDEBUG
const CGFunctionInfo &CallFnInfo =
CGM.getTypes().getFunctionInfo(ResultType, CallArgs, FPT->getExtInfo());
CGM.getTypes().arrangeFunctionCall(ResultType, CallArgs, FPT->getExtInfo(),
RequiredArgs::forPrototypePlus(FPT, 1));
assert(CallFnInfo.getRegParm() == FnInfo.getRegParm() &&
CallFnInfo.isNoReturn() == FnInfo.isNoReturn() &&
CallFnInfo.getCallingConvention() == FnInfo.getCallingConvention());
@ -398,7 +398,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
bool UseAvailableExternallyLinkage)
{
const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(GD);
const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(GD);
// FIXME: re-use FnInfo in this computation.
llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk);

View File

@ -66,7 +66,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
: Context(C), Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M),
TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags),
ABI(createCXXABI(*this)),
Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI, CGO),
Types(*this),
TBAA(0),
VTables(*this), ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0),
DebugInfo(0), ARCData(0), NoObjCARCExceptionsMetadata(0),
@ -580,7 +580,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
if (!IsIncompleteFunction)
SetLLVMFunctionAttributes(FD, getTypes().getFunctionInfo(GD), F);
SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F);
// Only a few attributes are set on declarations; these may later be
// overridden by a definition.
@ -1600,11 +1600,8 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
const FunctionDecl *D = cast<FunctionDecl>(GD.getDecl());
// Compute the function info and LLVM type.
const CGFunctionInfo &FI = getTypes().getFunctionInfo(GD);
bool variadic = false;
if (const FunctionProtoType *fpt = D->getType()->getAs<FunctionProtoType>())
variadic = fpt->isVariadic();
llvm::FunctionType *Ty = getTypes().GetFunctionType(FI, variadic);
const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
// Get or create the prototype for the function.
llvm::Constant *Entry = GetAddrOfFunction(GD, Ty);

View File

@ -15,6 +15,7 @@
#include "CGCall.h"
#include "CGCXXABI.h"
#include "CGRecordLayout.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
@ -26,11 +27,12 @@
using namespace clang;
using namespace CodeGen;
CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M,
const llvm::TargetData &TD, const ABIInfo &Info,
CGCXXABI &CXXABI, const CodeGenOptions &CGO)
: Context(Ctx), Target(Ctx.getTargetInfo()), TheModule(M), TheTargetData(TD),
TheABIInfo(Info), TheCXXABI(CXXABI), CodeGenOpts(CGO) {
CodeGenTypes::CodeGenTypes(CodeGenModule &CGM)
: Context(CGM.getContext()), Target(Context.getTargetInfo()),
TheModule(CGM.getModule()), TheTargetData(CGM.getTargetData()),
TheABIInfo(CGM.getTargetCodeGenInfo().getABIInfo()),
TheCXXABI(CGM.getCXXABI()),
CodeGenOpts(CGM.getCodeGenOpts()), CGM(CGM) {
SkippedLayout = false;
}
@ -473,16 +475,13 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
// The function type can be built; call the appropriate routines to
// build it.
const CGFunctionInfo *FI;
bool isVariadic;
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT)) {
FI = &getFunctionInfo(
FI = &arrangeFunctionType(
CanQual<FunctionProtoType>::CreateUnsafe(QualType(FPT, 0)));
isVariadic = FPT->isVariadic();
} else {
const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(FT);
FI = &getFunctionInfo(
FI = &arrangeFunctionType(
CanQual<FunctionNoProtoType>::CreateUnsafe(QualType(FNPT, 0)));
isVariadic = true;
}
// If there is something higher level prodding our CGFunctionInfo, then
@ -494,7 +493,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
} else {
// Otherwise, we're good to go, go ahead and convert it.
ResultType = GetFunctionType(*FI, isVariadic);
ResultType = GetFunctionType(*FI);
}
RecordsBeingLaidOut.erase(Ty);

View File

@ -52,10 +52,13 @@ namespace clang {
namespace CodeGen {
class CGCXXABI;
class CGRecordLayout;
class CodeGenModule;
class RequiredArgs;
/// CodeGenTypes - This class organizes the cross-module state that is used
/// while lowering AST types to LLVM types.
class CodeGenTypes {
// Some of this stuff should probably be left on the CGM.
ASTContext &Context;
const TargetInfo &Target;
llvm::Module &TheModule;
@ -63,6 +66,7 @@ class CodeGenTypes {
const ABIInfo &TheABIInfo;
CGCXXABI &TheCXXABI;
const CodeGenOptions &CodeGenOpts;
CodeGenModule &CGM;
/// The opaque type map for Objective-C interfaces. All direct
/// manipulation is done by the runtime interfaces, which are
@ -101,9 +105,7 @@ private:
llvm::DenseMap<const Type *, llvm::Type *> TypeCache;
public:
CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD,
const ABIInfo &Info, CGCXXABI &CXXABI,
const CodeGenOptions &Opts);
CodeGenTypes(CodeGenModule &CGM);
~CodeGenTypes();
const llvm::TargetData &getTargetData() const { return TheTargetData; }
@ -124,8 +126,7 @@ public:
llvm::Type *ConvertTypeForMem(QualType T);
/// GetFunctionType - Get the LLVM function type for \arg Info.
llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info,
bool IsVariadic);
llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info);
llvm::FunctionType *GetFunctionType(GlobalDecl GD);
@ -148,50 +149,66 @@ public:
/// getNullaryFunctionInfo - Get the function info for a void()
/// function with standard CC.
const CGFunctionInfo &getNullaryFunctionInfo();
const CGFunctionInfo &arrangeNullaryFunction();
/// getFunctionInfo - Get the function info for the specified function decl.
const CGFunctionInfo &getFunctionInfo(GlobalDecl GD);
// The arrangement methods are split into three families:
// - those meant to drive the signature and prologue/epilogue
// of a function declaration or definition,
// - those meant for the computation of the LLVM type for an abstract
// appearance of a function, and
// - those meant for performing the IR-generation of a call.
// They differ mainly in how they deal with optional (i.e. variadic)
// arguments, as well as unprototyped functions.
//
// Key points:
// - The CGFunctionInfo for emitting a specific call site must include
// entries for the optional arguments.
// - The function type used at the call site must reflect the formal
// signature of the declaration being called, or else the call will
// go awry.
// - For the most part, unprototyped functions are called by casting to
// a formal signature inferred from the specific argument types used
// at the call-site. However, some targets (e.g. x86-64) screw with
// this for compatibility reasons.
const CGFunctionInfo &getFunctionInfo(const FunctionDecl *FD);
const CGFunctionInfo &getFunctionInfo(const CXXMethodDecl *MD);
const CGFunctionInfo &getFunctionInfo(const ObjCMethodDecl *MD);
const CGFunctionInfo &getFunctionInfo(const CXXConstructorDecl *D,
CXXCtorType Type);
const CGFunctionInfo &getFunctionInfo(const CXXDestructorDecl *D,
CXXDtorType Type);
const CGFunctionInfo &arrangeGlobalDeclaration(GlobalDecl GD);
const CGFunctionInfo &arrangeFunctionDeclaration(const FunctionDecl *FD);
const CGFunctionInfo &arrangeFunctionDeclaration(QualType ResTy,
const FunctionArgList &Args,
const FunctionType::ExtInfo &Info,
bool isVariadic);
const CGFunctionInfo &getFunctionInfo(const CallArgList &Args,
const FunctionType *Ty) {
return getFunctionInfo(Ty->getResultType(), Args,
Ty->getExtInfo());
}
const CGFunctionInfo &arrangeObjCMethodDeclaration(const ObjCMethodDecl *MD);
const CGFunctionInfo &arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
QualType receiverType);
const CGFunctionInfo &getFunctionInfo(CanQual<FunctionProtoType> Ty);
const CGFunctionInfo &getFunctionInfo(CanQual<FunctionNoProtoType> Ty);
const CGFunctionInfo &arrangeCXXMethodDeclaration(const CXXMethodDecl *MD);
const CGFunctionInfo &arrangeCXXConstructorDeclaration(
const CXXConstructorDecl *D,
CXXCtorType Type);
const CGFunctionInfo &arrangeCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType Type);
/// getFunctionInfo - Get the function info for a member function of
/// the given type. This is used for calls through member function
/// pointers.
const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD,
const FunctionProtoType *FTP);
const CGFunctionInfo &arrangeFunctionCall(const CallArgList &Args,
const FunctionType *Ty);
const CGFunctionInfo &arrangeFunctionCall(QualType ResTy,
const CallArgList &args,
const FunctionType::ExtInfo &info,
RequiredArgs required);
/// getFunctionInfo - Get the function info for a function described by a
/// return type and argument types. If the calling convention is not
/// specified, the "C" calling convention will be used.
const CGFunctionInfo &getFunctionInfo(QualType ResTy,
const CallArgList &Args,
const FunctionType::ExtInfo &Info);
const CGFunctionInfo &getFunctionInfo(QualType ResTy,
const FunctionArgList &Args,
const FunctionType::ExtInfo &Info);
const CGFunctionInfo &arrangeFunctionType(CanQual<FunctionProtoType> Ty);
const CGFunctionInfo &arrangeFunctionType(CanQual<FunctionNoProtoType> Ty);
const CGFunctionInfo &arrangeCXXMethodType(const CXXRecordDecl *RD,
const FunctionProtoType *FTP);
/// Retrieves the ABI information for the given function signature.
/// This is the "core" routine to which all the others defer.
///
/// \param ArgTys - must all actually be canonical as params
const CGFunctionInfo &getFunctionInfo(CanQualType RetTy,
const SmallVectorImpl<CanQualType> &ArgTys,
const FunctionType::ExtInfo &Info);
/// \param argTypes - must all actually be canonical as params
const CGFunctionInfo &arrangeFunctionType(CanQualType returnType,
ArrayRef<CanQualType> argTypes,
const FunctionType::ExtInfo &info,
RequiredArgs args);
/// \brief Compute a new LLVM record layout object for the given record.
CGRecordLayout *ComputeRecordLayout(const RecordDecl *D,

View File

@ -218,8 +218,8 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
llvm::FunctionType *FTy =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
FPT->isVariadic());
CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodType(RD, FPT));
llvm::IntegerType *ptrdiff = getPtrDiffTy();
llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(ptrdiff, 1);
@ -511,8 +511,7 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
// Check whether the function has a computable LLVM signature.
if (Types.isFuncTypeConvertible(FPT)) {
// The function has a computable LLVM signature; use the correct type.
Ty = Types.GetFunctionType(Types.getFunctionInfo(MD),
FPT->isVariadic());
Ty = Types.GetFunctionType(Types.arrangeCXXMethodDeclaration(MD));
} else {
// Use an arbitrary non-function type to tell GetAddrOfFunction that the
// function type is incomplete.

View File

@ -98,8 +98,8 @@ unsigned TargetCodeGenInfo::getSizeOfUnwindException() const {
return 32;
}
bool TargetCodeGenInfo::isNoProtoCallVariadic(
const CodeGen::CGFunctionInfo &) const {
bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args,
const FunctionNoProtoType *fnType) const {
// The following conventions are known to require this to be false:
// x86_stdcall
// MIPS
@ -935,6 +935,17 @@ public:
X86_64ABIInfo(CodeGen::CodeGenTypes &CGT, bool hasavx) :
ABIInfo(CGT), HasAVX(hasavx) {}
bool isPassedUsingAVXType(QualType type) const {
unsigned neededInt, neededSSE;
ABIArgInfo info = classifyArgumentType(type, neededInt, neededSSE);
if (info.isDirect()) {
llvm::Type *ty = info.getCoerceToType();
if (llvm::VectorType *vectorTy = dyn_cast_or_null<llvm::VectorType>(ty))
return (vectorTy->getBitWidth() > 128);
}
return false;
}
virtual void computeInfo(CGFunctionInfo &FI) const;
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@ -960,6 +971,10 @@ public:
X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
: TargetCodeGenInfo(new X86_64ABIInfo(CGT, HasAVX)) {}
const X86_64ABIInfo &getABIInfo() const {
return static_cast<const X86_64ABIInfo&>(TargetCodeGenInfo::getABIInfo());
}
int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const {
return 7;
}
@ -980,33 +995,29 @@ public:
return X86AdjustInlineAsmType(CGF, Constraint, Ty);
}
bool isNoProtoCallVariadic(const CodeGen::CGFunctionInfo &FI) const {
bool isNoProtoCallVariadic(const CallArgList &args,
const FunctionNoProtoType *fnType) const {
// The default CC on x86-64 sets %al to the number of SSA
// registers used, and GCC sets this when calling an unprototyped
// function, so we override the default behavior. However, don't do
// that when AVX types are involved: the ABI explicitly states it is
// undefined, and it doesn't work in practice because of how the ABI
// defines varargs anyway.
if (FI.getCallingConvention() == llvm::CallingConv::C) {
if (fnType->getCallConv() == CC_Default || fnType->getCallConv() == CC_C) {
bool HasAVXType = false;
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
ie = FI.arg_end();
it != ie; ++it) {
if (it->info.isDirect()) {
llvm::Type *Ty = it->info.getCoerceToType();
if (llvm::VectorType *VTy = dyn_cast_or_null<llvm::VectorType>(Ty)) {
if (VTy->getBitWidth() > 128) {
HasAVXType = true;
break;
}
}
for (CallArgList::const_iterator
it = args.begin(), ie = args.end(); it != ie; ++it) {
if (getABIInfo().isPassedUsingAVXType(it->Ty)) {
HasAVXType = true;
break;
}
}
if (!HasAVXType)
return true;
}
return TargetCodeGenInfo::isNoProtoCallVariadic(FI);
return TargetCodeGenInfo::isNoProtoCallVariadic(args, fnType);
}
};

View File

@ -30,6 +30,7 @@ namespace clang {
class Decl;
namespace CodeGen {
class CallArgList;
class CodeGenModule;
class CodeGenFunction;
class CGFunctionInfo;
@ -161,7 +162,8 @@ namespace clang {
/// same way and some out-of-band information is passed for the
/// benefit of variadic callees, as is the case for x86-64.
/// In this case the ABI should be consulted.
virtual bool isNoProtoCallVariadic(const CodeGen::CGFunctionInfo &) const;
virtual bool isNoProtoCallVariadic(const CodeGen::CallArgList &args,
const FunctionNoProtoType *fnType) const;
};
}

View File

@ -20,8 +20,8 @@ void f1(A *a) {
}
void f2(A *a) {
// CHECK-X86-32: call void (i8*, i8*, i32, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, i32, ...)*)
// CHECK-X86-64: call void (i8*, i8*, i32, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, i32, ...)*)
// CHECK-X86-32: call void (i8*, i8*, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, ...)*)
// CHECK-X86-64: call void (i8*, i8*, i32, ...)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32, ...)*)
[a im2: 1, 2];
}
@ -33,8 +33,8 @@ void f2(A *a) {
[super im1: 1];
}
-(void) bar {
// CHECK-X86-32: call void (%struct._objc_super*, i8*, i32, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, i32, ...)*)
// CHECK-X86-64: call void (%struct._objc_super*, i8*, i32, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, i32, ...)*)
// CHECK-X86-32: call void (%struct._objc_super*, i8*, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, ...)*)
// CHECK-X86-64: call void (%struct._objc_super*, i8*, i32, ...)* bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper to void (%struct._objc_super*, i8*, i32, ...)*)
[super im2: 1, 2];
}