From: Chris Lattner Date: Tue, 24 Jun 2008 17:04:18 +0000 (+0000) Subject: "Support for Objective-C message sends which return structures. Also includes a... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8fdf32822be2238aa7db62d40e75b168b637ab7d;p=clang "Support for Objective-C message sends which return structures. Also includes a small fix for constant string handling that should have been in the last patch (sorry!) and a hook for generating selectors (rest of this implementation to follow in the next patch)." Patch by David Chisnall! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@52681 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 748ddde7b7..b9e850a473 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -86,6 +86,8 @@ public: void VisitOverloadExpr(const OverloadExpr *E); void VisitBinComma(const BinaryOperator *E); + void VisitObjCMessageExpr(ObjCMessageExpr *E); + void VisitConditionalOperator(const ConditionalOperator *CO); void VisitInitListExpr(InitListExpr *E); @@ -202,6 +204,16 @@ void AggExprEmitter::VisitCallExpr(const CallExpr *E) EmitAggregateCopy(DestPtr, RV.getAggregateAddr(), E->getType()); } +void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) +{ + RValue RV = RValue::getAggregate(CGF.EmitObjCMessageExpr(E)); + + // If the result is ignored, don't copy from the value. + if (DestPtr == 0) + return; + + EmitAggregateCopy(DestPtr, RV.getAggregateAddr(), E->getType()); +} void AggExprEmitter::VisitOverloadExpr(const OverloadExpr *E) { diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index a080a22602..22e49acb61 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -21,9 +21,88 @@ using namespace clang; using namespace CodeGen; +/// Emits an instance of NSConstantString representing the object. llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E){ - std::string S(E->getString()->getStrData(), E->getString()->getByteLength()); - return CGM.GetAddrOfConstantCFString(S); + return CGM.getObjCRuntime()->GenerateConstantString( + E->getString()->getStrData(), E->getString()->getByteLength()); +} + +/// Emit a selector. +llvm::Value *CodeGenFunction::EmitObjCSelectorExpr(const ObjCSelectorExpr *E) { + // Untyped selector. + // Note that this implementation allows for non-constant strings to be passed + // as arguments to @selector(). Currently, the only thing preventing this + // behaviour is the type checking in the front end. + return CGM.getObjCRuntime()->GetSelector(Builder, + CGM.GetAddrOfConstantString(E->getSelector().getName()), 0); +} + + + +llvm::Value *CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { + // Only the lookup mechanism and first two arguments of the method + // implementation vary between runtimes. We can get the receiver and + // arguments in generic code. + + CGObjCRuntime *Runtime = CGM.getObjCRuntime(); + const Expr *ReceiverExpr = E->getReceiver(); + bool isSuperMessage = false; + // Find the receiver + llvm::Value *Receiver; + if (!ReceiverExpr) { + const char * classname = E->getClassName()->getName(); + if (!strcmp(classname, "super")) { + classname = E->getMethodDecl()->getClassInterface()->getName(); + } + llvm::Value *ClassName = CGM.GetAddrOfConstantString(classname); + ClassName = Builder.CreateStructGEP(ClassName, 0); + Receiver = Runtime->LookupClass(Builder, ClassName); + } else if (dyn_cast(E->getReceiver())) { + isSuperMessage = true; + Receiver = LoadObjCSelf(); + } else { + Receiver = EmitScalarExpr(E->getReceiver()); + } + + // Process the arguments + unsigned ArgC = E->getNumArgs(); + llvm::SmallVector Args; + for (unsigned i = 0; i != ArgC; ++i) { + const Expr *ArgExpr = E->getArg(i); + QualType ArgTy = ArgExpr->getType(); + if (!hasAggregateLLVMType(ArgTy)) { + // Scalar argument is passed by-value. + Args.push_back(EmitScalarExpr(ArgExpr)); + } else if (ArgTy->isAnyComplexType()) { + // Make a temporary alloca to pass the argument. + llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy)); + EmitComplexExprIntoAddr(ArgExpr, DestMem, false); + Args.push_back(DestMem); + } else { + llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy)); + EmitAggExpr(ArgExpr, DestMem, false); + Args.push_back(DestMem); + } + } + + // Get the selector string + std::string SelStr = E->getSelector().getName(); + llvm::Constant *Selector = CGM.GetAddrOfConstantString(SelStr); + + llvm::Value *SelPtr = Builder.CreateStructGEP(Selector, 0); + if (isSuperMessage) { + const ObjCMethodDecl *OMD = dyn_cast(CurFuncDecl); + assert(OMD && "super is only valid in an Objective-C method"); + const char *SuperClass = OMD->getClassInterface()->getSuperClass()->getName(); + return Runtime->GenerateMessageSendSuper(Builder, ConvertType(E->getType()), + Receiver, SuperClass, + Receiver, SelPtr, + &Args[0], Args.size()); + } + return Runtime->GenerateMessageSend(Builder, ConvertType(E->getType()), + LoadObjCSelf(), + Receiver, SelPtr, + &Args[0], Args.size()); } /// Generate an Objective-C method. An Objective-C method is a C function with diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 2f02b13ee6..53eaf57560 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -405,11 +405,14 @@ llvm::Value *CGObjCGNU::GenerateMessageSend(llvm::IRBuilder &Builder, if (!ReturnTy->isSingleValueType()) { llvm::Value *Return = Builder.CreateAlloca(ReturnTy); Args.push_back(Return); - return Return; } Args.push_back(Receiver); Args.push_back(cmd); Args.insert(Args.end(), ArgV, ArgV+ArgC); + if (!ReturnTy->isSingleValueType()) { + Builder.CreateCall(imp, Args.begin(), Args.end()); + return Args[0]; + } return Builder.CreateCall(imp, Args.begin(), Args.end()); } @@ -887,7 +890,7 @@ llvm::Function *CGObjCGNU::MethodPreamble( bool isClassMethod, bool isVarArg) { std::vector Args; - if (!ReturnTy->isFirstClassType() && ReturnTy != llvm::Type::VoidTy) { + if (!ReturnTy->isSingleValueType() && ReturnTy != llvm::Type::VoidTy) { Args.push_back(llvm::PointerType::getUnqual(ReturnTy)); ReturnTy = llvm::Type::VoidTy; } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index b62042508c..82d4cb52a5 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -451,6 +451,10 @@ public: bool isSplat = false); llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E); + llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E); + llvm::Value *EmitObjCMessageExpr(const ObjCMessageExpr *E); + + //===--------------------------------------------------------------------===// // Expression Emission