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

Douglas Gregor dgregor at apple.com
Thu Feb 16 09:29:12 PST 2012


On Feb 15, 2012, at 8:26 PM, Eli Friedman wrote:

> On Wed, Feb 15, 2012 at 7:47 PM, Eli Friedman <eli.friedman at gmail.com> wrote:
>> 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...
> 
> Thinking about this a bit more, it's probably not such a good idea to
> make the conversion constexpr because there would be ABI implications.

Right, although one could certainly imagine that we could end up with constexpr lambdas in the not-too-distant future.

> But having the returned function in the AST would be convenient for
> mangling, it would reduce the amount of magic in IRGen, and it would
> make constant folding the conversion a bit more straightforward.
> Doug, any opinion?

It makes some parts of mangling and IR generation more difficult, e.g., we need to make sure we're sharing guard variables and the mangled names of local types between the two functions. That seems easier under the current design, where there's no duplication in the AST. I guess we could introduce a static member function __invoke with the same signature as operator() but leave IRgen to fill in the body. In that case, the AST could simply contain the body of the conversion to function pointer, since it would just be "return &__invoke" and could be constexpr'ified easily enough.

	- Doug





More information about the cfe-commits mailing list