diff options
author | Eli Friedman <eli.friedman@gmail.com> | 2012-02-16 03:47:28 +0000 |
---|---|---|
committer | Eli Friedman <eli.friedman@gmail.com> | 2012-02-16 03:47:28 +0000 |
commit | 21f6ed94b929beea31622f5e6b3890e51293cfad (patch) | |
tree | 1a9d77178c38321df2f71469ba234396ec5cc1b8 /lib/CodeGen/CGClass.cpp | |
parent | 5a0917d1367115d5fddfe7551f8634759217b54b (diff) |
Initial implementation of IRGen for the lambda conversion-to-function-pointer operator.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150660 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGClass.cpp')
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 94 |
1 files changed, 93 insertions, 1 deletions
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index b1096d267b..ed44679a88 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -1725,6 +1725,98 @@ void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) { 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()); } |