forked from OSchip/llvm-project
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).
llvm-svn: 151428
This commit is contained in:
parent
335c5a42e9
commit
2495ab08fc
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue