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

> On Wed, Feb 15, 2012 at 7:47 PM, Eli Friedman <[email protected]> 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


_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to