[cfe-commits] r150660 - in /cfe/trunk/lib/CodeGen: CGClass.cpp CodeGenFunction.h

Eli Friedman eli.friedman at gmail.com
Wed Feb 15 19:47:29 PST 2012


Author: efriedma
Date: Wed Feb 15 21:47:28 2012
New Revision: 150660

URL: http://llvm.org/viewvc/llvm-project?rev=150660&view=rev
Log:
Initial implementation of IRGen for the lambda conversion-to-function-pointer operator.


Modified:
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=150660&r1=150659&r2=150660&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Wed Feb 15 21:47:28 2012
@@ -1725,6 +1725,98 @@
   CGM.ErrorUnsupported(CurFuncDecl, "lambda conversion to block");
 }
 
+void CodeGenFunction::EmitLambdaThunkBody(llvm::Function *Fn,
+                                          const CGFunctionInfo &FnInfo,
+                                          const CXXRecordDecl *Lambda) {
+  DeclarationName Name
+    = getContext().DeclarationNames.getCXXOperatorName(OO_Call);
+  DeclContext::lookup_const_result Calls = Lambda->lookup(Name);
+  CXXMethodDecl *MD = cast<CXXMethodDecl>(*Calls.first++);
+  const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+  QualType ResultType = FPT->getResultType();
+
+  // Begin function
+  FunctionArgList FunctionArgs;
+  for (FunctionDecl::param_const_iterator I = MD->param_begin(),
+       E = MD->param_end(); I != E; ++I) {
+    ParmVarDecl *Param = *I;
+    FunctionArgs.push_back(Param);
+  }
+  StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs,
+                SourceLocation());
+
+  // Start building arguments for forwarding call
+  CallArgList CallArgs;
+
+  QualType ThisType = getContext().getPointerType(getContext().getRecordType(Lambda));
+  llvm::Value *ThisPtr = llvm::UndefValue::get(getTypes().ConvertType(ThisType));
+  CallArgs.add(RValue::get(ThisPtr), ThisType);
+
+  // Add the rest of the parameters.
+  for (FunctionDecl::param_const_iterator I = MD->param_begin(),
+       E = MD->param_end(); I != E; ++I) {
+    ParmVarDecl *param = *I;
+    EmitDelegateCallArg(CallArgs, param);
+  }
+
+  // Get the address of the call operator.
+  GlobalDecl GD(MD);
+  const CGFunctionInfo &CalleeFnInfo = CGM.getTypes().getFunctionInfo(GD);
+  llvm::Type *Ty =
+    CGM.getTypes().GetFunctionType(CalleeFnInfo, FPT->isVariadic());
+  llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty);
+
+  // Determine whether we have a return value slot to use.
+  ReturnValueSlot Slot;
+  if (!ResultType->isVoidType() &&
+      FnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
+      hasAggregateLLVMType(CurFnInfo->getReturnType()))
+    Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified());
+  
+  // Now emit our call.
+  RValue RV = EmitCall(CalleeFnInfo, Callee, Slot, CallArgs, MD);
+
+  // Forward the returned value
+  if (!ResultType->isVoidType() && Slot.isNull())
+    EmitReturnOfRValue(RV, ResultType);
+
+  // End the function.
+  FinishFunction();
+}
+
+llvm::Constant *
+CodeGenFunction::EmitLambdaConvertedFnPtr(const CXXMethodDecl *MD) {
+  QualType FnTy = MD->getResultType()->getPointeeType();
+  CanQual<FunctionProtoType> CanFnTy =
+      CGM.getContext().getCanonicalType(FnTy)->getAs<FunctionProtoType>();
+  llvm::FunctionType *FnLLVMTy = cast<llvm::FunctionType>(CGM.getTypes().ConvertType(FnTy));
+  const CXXRecordDecl *Lambda = MD->getParent();
+  const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(CanFnTy);
+
+  if (CanFnTy->isVariadic()) {
+    // FIXME: Making this work correctly is nasty because it requires either
+    // cloning the body of the call operator or making the call operator forward.
+    CGM.ErrorUnsupported(MD, "lambda conversion to variadic function");
+    return llvm::UndefValue::get(FnLLVMTy->getPointerTo());
+  }
+
+  // Build a declaration for the function which this function will
+  // return a pointer to.
+  // FIXME: Should the "thunk" actually be part of the AST?  That would allow
+  // the conversion to function pointer to be constexpr...
+  std::string MangledName =
+      (llvm::Twine(CurFn->getName()) + "_lambdacallthunk").str();
+  llvm::Function *Fn =
+      llvm::Function::Create(FnLLVMTy, llvm::Function::InternalLinkage,
+                            MangledName, &CGM.getModule());
+
+  // Emit the definition of the new function.
+  CodeGenFunction(CGM).EmitLambdaThunkBody(Fn, FnInfo, Lambda);
+  return Fn;
+}
+
 void CodeGenFunction::EmitLambdaToFunctionPointerBody(FunctionArgList &Args) {
-  CGM.ErrorUnsupported(CurFuncDecl, "lambda conversion to function");
+  const CXXMethodDecl *MD = cast<CXXMethodDecl>(CurFuncDecl);
+  EmitReturnOfRValue(RValue::get(EmitLambdaConvertedFnPtr(MD)),
+                     MD->getResultType());
 }

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=150660&r1=150659&r2=150660&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Feb 15 21:47:28 2012
@@ -1378,6 +1378,10 @@
 
   void EmitLambdaToBlockPointerBody(FunctionArgList &Args);
   void EmitLambdaToFunctionPointerBody(FunctionArgList &Args);
+  llvm::Constant *EmitLambdaConvertedFnPtr(const CXXMethodDecl *MD);
+  void EmitLambdaThunkBody(llvm::Function *Fn,
+                           const CGFunctionInfo &FnInfo,
+                           const CXXRecordDecl *Lambda);
 
   /// EmitReturnBlock - Emit the unified return block, trying to avoid its
   /// emission when possible.





More information about the cfe-commits mailing list