"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 748ddde..b9e850a 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -86,6 +86,8 @@
   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 @@
   
   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 a080a22..22e49ac 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<PreDefinedExpr>(E->getReceiver())) {
+    isSuperMessage = true;
+    Receiver = LoadObjCSelf();
+  } else {
+   Receiver = EmitScalarExpr(E->getReceiver());
+  }
+
+  // Process the arguments
+  unsigned ArgC = E->getNumArgs();
+  llvm::SmallVector<llvm::Value*, 16> 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<ObjCMethodDecl>(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 2f02b13..53eaf57 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -405,11 +405,14 @@
   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 @@
                                          bool isClassMethod,
                                          bool isVarArg) {
   std::vector<const llvm::Type*> 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 b620425..82d4cb5 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -451,6 +451,10 @@
                           bool isSplat = false);
   
   llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
+  llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E);
+  llvm::Value *EmitObjCMessageExpr(const ObjCMessageExpr *E);
+
+
 
   //===--------------------------------------------------------------------===//
   //                           Expression Emission