diff options
author | Eli Friedman <eli.friedman@gmail.com> | 2012-02-25 02:48:22 +0000 |
---|---|---|
committer | Eli Friedman <eli.friedman@gmail.com> | 2012-02-25 02:48:22 +0000 |
commit | 64bee65a3436e3f0c352fcfe2130676f3502cffe (patch) | |
tree | 9154d934a177c762072a49a0fa5d0813c37c780a | |
parent | e1d4330adaaa7faf093e725c9c993207eb2d778a (diff) |
Work-in-progress for lambda conversion-to-block operator. Still need to implement the retain+autorelease outside of ARC, and there's a bug that causes the generated code to crash in ARC (which I think is unrelated to my code, although I'm not completely sure).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151428 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 19 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 83 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 7 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 16 |
5 files changed, 96 insertions, 32 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index a91a34153f..f6aa9b4b48 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -624,7 +624,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { // Using the computed layout, generate the actual block function. llvm::Constant *blockFn = CodeGenFunction(CGM).GenerateBlockFunction(CurGD, blockInfo, - CurFuncDecl, LocalDeclMap); + CurFuncDecl, LocalDeclMap, + InLambdaConversionToBlock); blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy); // If there is nothing to capture, we can emit this as a global block. @@ -699,6 +700,11 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { src = Builder.CreateStructGEP(LoadBlockStruct(), enclosingCapture.getIndex(), "block.capture.addr"); + } else if (InLambdaConversionToBlock) { + // The lambda capture in a lambda's conversion-to-block-pointer is + // special; we know its argument is an lvalue we can simply emit. + CXXConstructExpr *CE = cast<CXXConstructExpr>(ci->getCopyExpr()); + src = EmitLValue(CE->getArg(0)).getAddress(); } else { // This is a [[type]]*. src = LocalDeclMap[variable]; @@ -921,7 +927,8 @@ CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *blockExpr, llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; blockFn = CodeGenFunction(*this).GenerateBlockFunction(GlobalDecl(), blockInfo, - 0, LocalDeclMap); + 0, LocalDeclMap, + false); } blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy); @@ -975,7 +982,8 @@ llvm::Function * CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const CGBlockInfo &blockInfo, const Decl *outerFnDecl, - const DeclMapTy &ldm) { + const DeclMapTy &ldm, + bool IsLambdaConversionToBlock) { const BlockDecl *blockDecl = blockInfo.getBlockDecl(); // Check if we should generate debug info for this block function. @@ -1092,7 +1100,10 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint(); --entry_ptr; - EmitStmt(blockDecl->getBody()); + if (IsLambdaConversionToBlock) + EmitLambdaBlockInvokeBody(); + else + EmitStmt(blockDecl->getBody()); // Remember where we were... llvm::BasicBlock *resume = Builder.GetInsertBlock(); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 2cea434f62..618a3f86cd 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "CGBlocks.h" #include "CGDebugInfo.h" #include "CodeGenFunction.h" #include "clang/AST/CXXInheritance.h" @@ -1726,33 +1727,17 @@ CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E, return CGM.GetAddrOfFunction(MD, fnType); } -void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) { - CGM.ErrorUnsupported(CurFuncDecl, "lambda conversion to block"); -} - -void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) { - const CXXRecordDecl *Lambda = MD->getParent(); +void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *Lambda, + CallArgList &CallArgs) { + // Lookup the call operator DeclarationName Name = getContext().DeclarationNames.getCXXOperatorName(OO_Call); DeclContext::lookup_const_result Calls = Lambda->lookup(Name); CXXMethodDecl *CallOperator = cast<CXXMethodDecl>(*Calls.first++); - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const FunctionProtoType *FPT = + CallOperator->getType()->getAs<FunctionProtoType>(); QualType ResultType = FPT->getResultType(); - // 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(CallOperator); const CGFunctionInfo &CalleeFnInfo = @@ -1776,11 +1761,67 @@ void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) { EmitReturnOfRValue(RV, ResultType); } +void CodeGenFunction::EmitLambdaBlockInvokeBody() { + const BlockDecl *BD = BlockInfo->getBlockDecl(); + const VarDecl *variable = BD->capture_begin()->getVariable(); + const CXXRecordDecl *Lambda = variable->getType()->getAsCXXRecordDecl(); + + // Start building arguments for forwarding call + CallArgList CallArgs; + + QualType ThisType = getContext().getPointerType(getContext().getRecordType(Lambda)); + llvm::Value *ThisPtr = GetAddrOfBlockDecl(variable, false); + CallArgs.add(RValue::get(ThisPtr), ThisType); + + // Add the rest of the parameters. + for (BlockDecl::param_const_iterator I = BD->param_begin(), + E = BD->param_end(); I != E; ++I) { + ParmVarDecl *param = *I; + EmitDelegateCallArg(CallArgs, param); + } + + EmitForwardingCallToLambda(Lambda, CallArgs); +} + +void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) { + if (cast<CXXMethodDecl>(CurFuncDecl)->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(CurFuncDecl, "lambda conversion to variadic function"); + return; + } + + InLambdaConversionToBlock = true; + EmitFunctionBody(Args); + InLambdaConversionToBlock = false; +} + +void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) { + const CXXRecordDecl *Lambda = MD->getParent(); + + // 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); + } + + EmitForwardingCallToLambda(Lambda, CallArgs); +} + void CodeGenFunction::EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD) { if (MD->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; } EmitLambdaDelegatingInvokeBody(MD); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 47176bd8ec..5d18169695 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -32,7 +32,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) Target(CGM.getContext().getTargetInfo()), Builder(cgm.getModule().getContext()), AutoreleaseResult(false), BlockInfo(0), BlockPointer(0), - LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1), + LambdaThisCaptureField(0), InLambdaConversionToBlock(false), + NormalCleanupDest(0), NextCleanupDestIndex(1), FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0), DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0), diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 65338bf8ee..71f2362311 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -601,6 +601,7 @@ public: llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields; FieldDecl *LambdaThisCaptureField; + bool InLambdaConversionToBlock; /// \brief A mapping from NRVO variables to the flags used to indicate /// when the NRVO has been applied to this variable. @@ -1335,7 +1336,8 @@ public: llvm::Function *GenerateBlockFunction(GlobalDecl GD, const CGBlockInfo &Info, const Decl *OuterFuncDecl, - const DeclMapTy &ldm); + const DeclMapTy &ldm, + bool IsLambdaConversionToBlock); llvm::Constant *GenerateCopyHelperFunction(const CGBlockInfo &blockInfo); llvm::Constant *GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo); @@ -1376,7 +1378,10 @@ public: void EmitDestructorBody(FunctionArgList &Args); void EmitFunctionBody(FunctionArgList &Args); + void EmitForwardingCallToLambda(const CXXRecordDecl *Lambda, + CallArgList &CallArgs); void EmitLambdaToBlockPointerBody(FunctionArgList &Args); + void EmitLambdaBlockInvokeBody(); void EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD); void EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a2180be53c..1f5255dae7 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -8868,11 +8868,17 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( } Block->setParams(BlockParams); - // Add capture. The capture is uses a fake (NULL) variable, since we don't - // actually want to have to name a capture variable. However, the - // initializer copy-initializes the lambda object. - BlockDecl::Capture Capture(/*Variable=*/0, /*ByRef=*/false, /*Nested=*/false, - /*Copy=*/Init.take()); + // Add capture. The capture uses a fake variable, which doesn't correspond + // to any actual memory location. However, the initializer copy-initializes + // the lambda object. + TypeSourceInfo *CapVarTSI = + Context.getTrivialTypeSourceInfo(DerefThis->getType()); + VarDecl *CapVar = VarDecl::Create(Context, Block, Conv->getLocation(), + Conv->getLocation(), 0, + DerefThis->getType(), CapVarTSI, + SC_None, SC_None); + BlockDecl::Capture Capture(/*Variable=*/CapVar, /*ByRef=*/false, + /*Nested=*/false, /*Copy=*/Init.take()); Block->setCaptures(Context, &Capture, &Capture + 1, /*CapturesCXXThis=*/false); |