From 19cd87eb5fb3c197e631ce08fd52c446c4d4e8f1 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Sat, 30 Aug 2008 03:02:31 +0000 Subject: [PATCH] Refactor handling of calls: - Added CodeGenFunction::EmitCall which just takes the callee, return type, and a list of (Value*,QualType) pairs. - Added CodeGenFunction::EmitCallArg which handles emitting code for a call argument and turning it into an appropriate (Value*,QualType) pair. - Changed Objective-C runtime interface so that the actual emission of arguments for message sends is (once again) done in the code to emit a message send. No intended functionality change, this is prep work for better ABI support and for Objective-C property setter support. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55560 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGExpr.cpp | 99 +++++++++++++++++++---------------- lib/CodeGen/CGObjC.cpp | 10 +++- lib/CodeGen/CGObjCGNU.cpp | 36 ++++++++----- lib/CodeGen/CGObjCMac.cpp | 83 +++++++++++++++++++++-------- lib/CodeGen/CGObjCRuntime.h | 10 ++-- lib/CodeGen/CodeGenFunction.h | 13 +++-- 6 files changed, 158 insertions(+), 93 deletions(-) diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index d3872c12dd..c8aa26155e 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -822,66 +822,77 @@ RValue CodeGenFunction::EmitCallExpr(llvm::Value *Callee, QualType FnType, // type. FnType = FnType->getAsPointerType()->getPointeeType(); QualType ResultType = FnType->getAsFunctionType()->getResultType(); - return EmitCallExprExt(Callee, ResultType, ArgBeg, ArgEnd, 0, 0); + + CallArgList Args; + for (CallExpr::const_arg_iterator I = ArgBeg; I != ArgEnd; ++I) + EmitCallArg(*I, Args); + + return EmitCall(Callee, ResultType, Args); } -RValue CodeGenFunction::EmitCallExprExt(llvm::Value *Callee, - QualType ResultType, - CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd, - llvm::Value **ExtraArgs, - unsigned NumExtraArgs) { - llvm::SmallVector Args; +void CodeGenFunction::EmitCallArg(const Expr *E, CallArgList &Args) { + QualType ArgTy = E->getType(); + llvm::Value *ArgValue; + if (!hasAggregateLLVMType(ArgTy)) { + // Scalar argument is passed by-value. + ArgValue = EmitScalarExpr(E); + } else if (ArgTy->isAnyComplexType()) { + // Make a temporary alloca to pass the argument. + ArgValue = CreateTempAlloca(ConvertType(ArgTy)); + EmitComplexExprIntoAddr(E, ArgValue, false); + } else { + ArgValue = CreateTempAlloca(ConvertType(ArgTy)); + EmitAggExpr(E, ArgValue, false); + } + + Args.push_back(std::make_pair(ArgValue, E->getType())); +} + +RValue CodeGenFunction::EmitCall(llvm::Value *Callee, + QualType ResultType, + const CallArgList &CallArgs) { + llvm::SmallVector Args; + llvm::Value *TempArg0 = 0; + // Handle struct-return functions by passing a pointer to the location that // we would like to return into. if (hasAggregateLLVMType(ResultType)) { // Create a temporary alloca to hold the result of the call. :( - Args.push_back(CreateTempAlloca(ConvertType(ResultType))); - // FIXME: set the stret attribute on the argument. + TempArg0 = CreateTempAlloca(ConvertType(ResultType)); + Args.push_back(TempArg0); } - Args.insert(Args.end(), ExtraArgs, ExtraArgs + NumExtraArgs); - - for (CallExpr::const_arg_iterator I = ArgBeg; I != ArgEnd; ++I) { - QualType ArgTy = I->getType(); - - if (!hasAggregateLLVMType(ArgTy)) { - // Scalar argument is passed by-value. - Args.push_back(EmitScalarExpr(*I)); - } else if (ArgTy->isAnyComplexType()) { - // Make a temporary alloca to pass the argument. - llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy)); - EmitComplexExprIntoAddr(*I, DestMem, false); - Args.push_back(DestMem); - } else { - llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy)); - EmitAggExpr(*I, DestMem, false); - Args.push_back(DestMem); - } - } + for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end(); + I != E; ++I) + Args.push_back(I->first); llvm::CallInst *CI = Builder.CreateCall(Callee,&Args[0],&Args[0]+Args.size()); // Note that there is parallel code in SetFunctionAttributes in CodeGenModule llvm::SmallVector ParamAttrList; - if (hasAggregateLLVMType(ResultType)) + unsigned Index = 1; + if (TempArg0) { ParamAttrList.push_back( - llvm::ParamAttrsWithIndex::get(1, llvm::ParamAttr::StructRet)); - unsigned increment = NumExtraArgs + (hasAggregateLLVMType(ResultType) ? 2 : 1); - - unsigned i = 0; - for (CallExpr::const_arg_iterator I = ArgBeg; I != ArgEnd; ++I, ++i) { - QualType ParamType = I->getType(); + llvm::ParamAttrsWithIndex::get(Index, llvm::ParamAttr::StructRet)); + ++Index; + } + + for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end(); + I != E; ++I, ++Index) { + QualType ParamType = I->second; unsigned ParamAttrs = 0; if (ParamType->isRecordType()) ParamAttrs |= llvm::ParamAttr::ByVal; - if (ParamType->isSignedIntegerType() && ParamType->isPromotableIntegerType()) - ParamAttrs |= llvm::ParamAttr::SExt; - if (ParamType->isUnsignedIntegerType() && ParamType->isPromotableIntegerType()) - ParamAttrs |= llvm::ParamAttr::ZExt; + if (ParamType->isPromotableIntegerType()) { + if (ParamType->isSignedIntegerType()) { + ParamAttrs |= llvm::ParamAttr::SExt; + } else if (ParamType->isUnsignedIntegerType()) { + ParamAttrs |= llvm::ParamAttr::ZExt; + } + } if (ParamAttrs) - ParamAttrList.push_back(llvm::ParamAttrsWithIndex::get(i + increment, + ParamAttrList.push_back(llvm::ParamAttrsWithIndex::get(Index, ParamAttrs)); } CI->setParamAttrs(llvm::PAListPtr::get(ParamAttrList.begin(), @@ -892,15 +903,15 @@ RValue CodeGenFunction::EmitCallExprExt(llvm::Value *Callee, if (CI->getType() != llvm::Type::VoidTy) CI->setName("call"); else if (ResultType->isAnyComplexType()) - return RValue::getComplex(LoadComplexFromAddr(Args[0], false)); + return RValue::getComplex(LoadComplexFromAddr(TempArg0, false)); else if (hasAggregateLLVMType(ResultType)) // Struct return. - return RValue::getAggregate(Args[0]); + return RValue::getAggregate(TempArg0); else { // void return. assert(ResultType->isVoidType() && "Should only have a void expr here"); CI = 0; } - return RValue::get(CI); + return RValue::get(CI); } diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 624b24aa75..2a808f8e05 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -78,15 +78,21 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { Receiver = EmitScalarExpr(E->getReceiver()); } + CallArgList Args; + for (CallExpr::const_arg_iterator i = E->arg_begin(), e = E->arg_end(); + i != e; ++i) + EmitCallArg(*i, Args); + if (isSuperMessage) { // super is only valid in an Objective-C method const ObjCMethodDecl *OMD = cast(CurFuncDecl); return Runtime.GenerateMessageSendSuper(*this, E, OMD->getClassInterface(), Receiver, - isClassMessage); + isClassMessage, + Args); } - return Runtime.GenerateMessageSend(*this, E, Receiver, isClassMessage); + return Runtime.GenerateMessageSend(*this, E, Receiver, isClassMessage, Args); } /// StartObjCMethod - Begin emission of an ObjCMethod. This generates diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 1b254c0a26..e5a5d05331 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -98,13 +98,15 @@ public: GenerateMessageSend(CodeGen::CodeGenFunction &CGF, const ObjCMessageExpr *E, llvm::Value *Receiver, - bool IsClassMessage); + bool IsClassMessage, + const CallArgList &CallArgs); virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, const ObjCMessageExpr *E, const ObjCInterfaceDecl *Class, llvm::Value *Receiver, - bool IsClassMessage); + bool IsClassMessage, + const CallArgList &CallArgs); virtual llvm::Value *GetClass(llvm::IRBuilder<> &Builder, const ObjCInterfaceDecl *OID); virtual llvm::Value *GetSelector(llvm::IRBuilder<> &Builder, Selector Sel); @@ -240,7 +242,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, const ObjCMessageExpr *E, const ObjCInterfaceDecl *Class, llvm::Value *Receiver, - bool IsClassMessage) { + bool IsClassMessage, + const CallArgList &CallArgs) { const ObjCInterfaceDecl *SuperClass = Class->getSuperClass(); const llvm::Type *ReturnTy = CGM.getTypes().ConvertType(E->getType()); // TODO: This should be cached, not looked up every time. @@ -273,11 +276,13 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, lookupArgs+2); // Call the method - llvm::Value *Args[2]; - Args[0] = Receiver; - Args[1] = cmd; - return CGF.EmitCallExprExt(imp, E->getType(), E->arg_begin(), E->arg_end(), - Args, 2); + CallArgList ActualArgs; + ActualArgs.push_back(std::make_pair(Receiver, + CGF.getContext().getObjCIdType())); + ActualArgs.push_back(std::make_pair(cmd, + CGF.getContext().getObjCSelType())); + ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); + return CGF.EmitCall(imp, E->getType(), ActualArgs); } /// Generate code for a message send expression. @@ -285,7 +290,8 @@ CodeGen::RValue CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, const ObjCMessageExpr *E, llvm::Value *Receiver, - bool IsClassMessage) { + bool IsClassMessage, + const CallArgList &CallArgs) { const llvm::Type *ReturnTy = CGM.getTypes().ConvertType(E->getType()); llvm::Value *cmd = GetSelector(CGF.Builder, E->getSelector()); @@ -316,11 +322,13 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, llvm::Value *imp = CGF.Builder.CreateCall2(lookupFunction, Receiver, cmd); // Call the method. - llvm::Value *Args[2]; - Args[0] = Receiver; - Args[1] = cmd; - return CGF.EmitCallExprExt(imp, E->getType(), E->arg_begin(), E->arg_end(), - Args, 2); + CallArgList ActualArgs; + ActualArgs.push_back(std::make_pair(Receiver, + CGF.getContext().getObjCIdType())); + ActualArgs.push_back(std::make_pair(cmd, + CGF.getContext().getObjCSelType())); + ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); + return CGF.EmitCall(imp, E->getType(), ActualArgs); } /// Generates a MethodList. Used in construction of a objc_class and diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 2f0158a9d4..3b4309d894 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -55,6 +55,11 @@ public: /// (typeof(Protocol)) const llvm::Type *ExternalProtocolPtrTy; + // SuperCTy - clang type for struct objc_super. + QualType SuperCTy; + // SuperPtrCTy - clang type for struct objc_super *. + QualType SuperPtrCTy; + /// SuperTy - LLVM type for struct objc_super. const llvm::StructType *SuperTy; /// SuperPtrTy - LLVM type for struct objc_super *. @@ -216,7 +221,9 @@ private: CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF, const ObjCMessageExpr *E, llvm::Value *Arg0, - bool IsSuper); + QualType Arg0Ty, + bool IsSuper, + const CallArgList &CallArgs); /// EmitIvarList - Emit the ivar list for the given /// implementation. If ForClass is true the list of class ivars @@ -332,14 +339,16 @@ public: virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, const ObjCMessageExpr *E, llvm::Value *Receiver, - bool IsClassMessage); + bool IsClassMessage, + const CallArgList &CallArgs); virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, const ObjCMessageExpr *E, const ObjCInterfaceDecl *Class, llvm::Value *Receiver, - bool IsClassMessage); + bool IsClassMessage, + const CallArgList &CallArgs); virtual llvm::Value *GetClass(llvm::IRBuilder<> &Builder, const ObjCInterfaceDecl *ID); @@ -422,7 +431,8 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, const ObjCMessageExpr *E, const ObjCInterfaceDecl *Class, llvm::Value *Receiver, - bool IsClassMessage) { + bool IsClassMessage, + const CallArgList &CallArgs) { // Create and init a super structure; this is a (receiver, class) // pair we will pass to objc_msgSendSuper. llvm::Value *ObjCSuper = @@ -442,42 +452,54 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, } else { Target = EmitClassRef(CGF.Builder, Class->getSuperClass()); } + // FIXME: We shouldn't need to do this cast, rectify the ASTContext + // and ObjCTypes types. + const llvm::Type *ClassTy = + CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType()); + Target = CGF.Builder.CreateBitCast(Target, ClassTy); CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1)); - return EmitMessageSend(CGF, E, ObjCSuper, true); + return EmitMessageSend(CGF, E, + ObjCSuper, ObjCTypes.SuperPtrCTy, + true, CallArgs); } /// Generate code for a message send expression. CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, const ObjCMessageExpr *E, llvm::Value *Receiver, - bool IsClassMessage) { + bool IsClassMessage, + const CallArgList &CallArgs) { llvm::Value *Arg0 = CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy, "tmp"); - return EmitMessageSend(CGF, E, Arg0, false); + return EmitMessageSend(CGF, E, + Arg0, CGF.getContext().getObjCIdType(), + false, CallArgs); } CodeGen::RValue CGObjCMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, const ObjCMessageExpr *E, llvm::Value *Arg0, - bool IsSuper) { - llvm::Value *Args[2]; - Args[0] = Arg0; - Args[1] = EmitSelector(CGF.Builder, E->getSelector()); + QualType Arg0Ty, + bool IsSuper, + const CallArgList &CallArgs) { + CallArgList ActualArgs; + ActualArgs.push_back(std::make_pair(Arg0, Arg0Ty)); + ActualArgs.push_back(std::make_pair(EmitSelector(CGF.Builder, + E->getSelector()), + CGF.getContext().getObjCSelType())); + ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); // FIXME: This is a hack, we are implicitly coordinating with // EmitCallExprExt, which will move the return type to the first // parameter and set the structure return flag. See // getMessageSendFn(). - const llvm::Type *ReturnTy = CGM.getTypes().ConvertType(E->getType()); - return CGF.EmitCallExprExt(ObjCTypes.getMessageSendFn(IsSuper, ReturnTy), - E->getType(), - E->arg_begin(), - E->arg_end(), - Args, 2); + return CGF.EmitCall(ObjCTypes.getMessageSendFn(IsSuper, ReturnTy), + E->getType(), + ActualArgs); } llvm::Value *CGObjCMac::GenerateProtocolRef(llvm::IRBuilder<> &Builder, @@ -1820,12 +1842,27 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) NULL); CGM.getModule().addTypeName("struct._objc_category", CategoryTy); - SuperTy = - llvm::StructType::get(ObjectPtrTy, - ClassPtrTy, - NULL); - CGM.getModule().addTypeName("struct._objc_super", - SuperTy); + // I'm not sure I like this. The implicit coordination is a bit + // gross. We should solve this in a reasonable fashion because this + // is a pretty common task (match some runtime data structure with + // an LLVM data structure). + + // FIXME: This is leaked. + // FIXME: Merge with rewriter code? + RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0, + SourceLocation(), + &Ctx.Idents.get("_objc_super"), 0); + FieldDecl *FieldDecls[2]; + FieldDecls[0] = FieldDecl::Create(Ctx, SourceLocation(), 0, + Ctx.getObjCIdType()); + FieldDecls[1] = FieldDecl::Create(Ctx, SourceLocation(), 0, + Ctx.getObjCClassType()); + RD->defineBody(FieldDecls, 2); + + SuperCTy = Ctx.getTagDeclType(RD); + SuperPtrCTy = Ctx.getPointerType(SuperCTy); + + SuperTy = cast(Types.ConvertType(SuperCTy)); SuperPtrTy = llvm::PointerType::getUnqual(SuperTy); // Global metadata structures diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index e373ef20a7..54591a331c 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -43,6 +43,8 @@ namespace clang { class ObjCProtocolDecl; class Selector; + typedef llvm::SmallVector, 16> CallArgList; + namespace CodeGen { class CodeGenModule; @@ -81,7 +83,8 @@ public: GenerateMessageSend(CodeGen::CodeGenFunction &CGF, const ObjCMessageExpr *E, llvm::Value *Receiver, - bool IsClassMessage) = 0; + bool IsClassMessage, + const CallArgList &CallArgs) = 0; /// Generate an Objective-C message send operation to the super /// class initiated in a method for Class and with the given Self @@ -91,7 +94,8 @@ public: const ObjCMessageExpr *E, const ObjCInterfaceDecl *Class, llvm::Value *Self, - bool IsClassMessage) = 0; + bool IsClassMessage, + const CallArgList &CallArgs) = 0; /// Emit the code to return the named protocol as an object, as in a /// @protocol expression. @@ -120,7 +124,7 @@ public: /// return true, otherwise instance variables will be accessed directly from /// the structure. If this returns true then @defs is invalid for this /// runtime and a warning should be generated. - virtual bool LateBoundIVars() { return false; } + virtual bool LateBoundIVars() const { return false; } }; /// Creates an instance of an Objective-C runtime class. diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index d1f3a6a539..e00c66552f 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -299,6 +299,12 @@ public: // Scalar Expression Emission //===--------------------------------------------------------------------===// + typedef llvm::SmallVector, 16> CallArgList; + void EmitCallArg(const Expr *E, CallArgList &Args); + RValue EmitCall(llvm::Value *Callee, + QualType ResultType, + const CallArgList &Args); + RValue EmitCallExpr(const CallExpr *E); RValue EmitCallExpr(Expr *FnExpr, CallExpr::const_arg_iterator ArgBeg, @@ -308,13 +314,6 @@ public: CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); - RValue EmitCallExprExt(llvm::Value *Callee, - QualType ResultType, - CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd, - llvm::Value **ExtraArgs, - unsigned NumExtraArgs); - RValue EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E); -- 2.40.0