Add codegen support for __block variables to call _Block_object_dispose as necessary.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66117 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 00bda46..89b2b5f 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -34,8 +34,6 @@
llvm::Constant *CodeGenFunction::BuildDescriptorBlockDecl(uint64_t Size) {
- const llvm::PointerType *PtrToInt8Ty
- = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
const llvm::Type *UnsignedLongTy
= CGM.getTypes().ConvertType(getContext().UnsignedLongTy);
llvm::Constant *C;
@@ -78,8 +76,6 @@
if (NSConcreteGlobalBlock)
return NSConcreteGlobalBlock;
- const llvm::PointerType *PtrToInt8Ty
- = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
// FIXME: We should have a CodeGenModule::AddRuntimeVariable that does the
// same thing as CreateRuntimeFunction if there's already a variable with the
// same name.
@@ -96,8 +92,6 @@
if (NSConcreteStackBlock)
return NSConcreteStackBlock;
- const llvm::PointerType *PtrToInt8Ty
- = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
// FIXME: We should have a CodeGenModule::AddRuntimeVariable that does the
// same thing as CreateRuntimeFunction if there's already a variable with the
// same name.
@@ -164,8 +158,6 @@
// __isa
C = CGM.getNSConcreteStackBlock();
- const llvm::PointerType *PtrToInt8Ty
- = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty);
Elts.push_back(C);
@@ -335,9 +327,6 @@
if (GenericBlockLiteralType)
return GenericBlockLiteralType;
- const llvm::Type *Int8PtrTy =
- llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
-
const llvm::Type *BlockDescPtrTy =
llvm::PointerType::getUnqual(getBlockDescriptorType());
@@ -351,10 +340,10 @@
// void (*__invoke)(void *);
// struct __block_descriptor *__descriptor;
// };
- GenericBlockLiteralType = llvm::StructType::get(Int8PtrTy,
+ GenericBlockLiteralType = llvm::StructType::get(PtrToInt8Ty,
IntTy,
IntTy,
- Int8PtrTy,
+ PtrToInt8Ty,
BlockDescPtrTy,
NULL);
@@ -368,9 +357,6 @@
if (GenericExtendedBlockLiteralType)
return GenericExtendedBlockLiteralType;
- const llvm::Type *Int8PtrTy =
- llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
-
const llvm::Type *BlockDescPtrTy =
llvm::PointerType::getUnqual(getBlockDescriptorType());
@@ -386,13 +372,13 @@
// void *__copy_func_helper_decl;
// void *__destroy_func_decl;
// };
- GenericExtendedBlockLiteralType = llvm::StructType::get(Int8PtrTy,
+ GenericExtendedBlockLiteralType = llvm::StructType::get(PtrToInt8Ty,
IntTy,
IntTy,
- Int8PtrTy,
+ PtrToInt8Ty,
BlockDescPtrTy,
- Int8PtrTy,
- Int8PtrTy,
+ PtrToInt8Ty,
+ PtrToInt8Ty,
NULL);
getModule().addTypeName("struct.__block_literal_extended_generic",
@@ -678,8 +664,6 @@
}
llvm::Value *BlockFunction::BuildCopyHelper(int flag) {
- const llvm::PointerType *PtrToInt8Ty
- = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
// FIXME: implement
llvm::Value *V = llvm::ConstantInt::get(llvm::Type::Int32Ty, 43);
V = Builder.CreateIntToPtr(V, PtrToInt8Ty, "tmp");
@@ -688,11 +672,33 @@
}
llvm::Value *BlockFunction::BuildDestroyHelper(int flag) {
- const llvm::PointerType *PtrToInt8Ty
- = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
// FIXME: implement
llvm::Value *V = llvm::ConstantInt::get(llvm::Type::Int32Ty, 44);
V = Builder.CreateIntToPtr(V, PtrToInt8Ty, "tmp");
V = Builder.CreateBitCast(V, PtrToInt8Ty, "tmp");
return V;
}
+
+llvm::Value *BlockFunction::getBlockObjectDispose() {
+ if (CGM.BlockObjectDispose == 0) {
+ const llvm::FunctionType *FTy;
+ std::vector<const llvm::Type*> ArgTys;
+ const llvm::Type *ResultType = llvm::Type::VoidTy;
+ ArgTys.push_back(PtrToInt8Ty);
+ ArgTys.push_back(llvm::Type::Int32Ty);
+ FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
+ CGM.BlockObjectDispose
+ = CGM.CreateRuntimeFunction(FTy, "_Block_object_dispose");
+ }
+ return CGM.BlockObjectDispose;
+}
+
+void BlockFunction::BuildBlockRelease(const VarDecl &D, llvm::Value *DeclPtr) {
+ llvm::Value *F = getBlockObjectDispose();
+ llvm::Value *N, *V;
+ V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
+ V = Builder.CreateLoad(V, false);
+ V = Builder.CreateBitCast(V, PtrToInt8Ty);
+ N = llvm::ConstantInt::get(llvm::Type::Int32Ty, BLOCK_FIELD_IS_BYREF);
+ Builder.CreateCall2(F, V, N);
+}
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index bef7459..3b9cc50 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -94,19 +94,26 @@
int GlobalUniqueCount;
} Block;
+ llvm::Value *BlockObjectDispose;
+ const llvm::Type *PtrToInt8Ty;
+
BlockModule(ASTContext &C, llvm::Module &M, const llvm::TargetData &TD,
CodeGenTypes &T, CodeGenModule &CodeGen)
: Context(C), TheModule(M), TheTargetData(TD), Types(T),
CGM(CodeGen),
NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockDescriptorType(0),
- GenericBlockLiteralType(0) {
+ GenericBlockLiteralType(0), BlockObjectDispose(0) {
Block.GlobalUniqueCount = 0;
+ PtrToInt8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
}
};
class BlockFunction : public BlockBase {
+ CodeGenModule &CGM;
+
public:
- enum {
+ const llvm::Type *PtrToInt8Ty;
+ enum {
BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)),
block, ... */
BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */
@@ -140,7 +147,10 @@
CGBuilderTy &Builder;
- BlockFunction(CGBuilderTy &B) : Builder(B) { }
+ BlockFunction(CodeGenModule &cgm, CGBuilderTy &B)
+ : CGM(cgm), Builder(B) {
+ PtrToInt8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ }
ImplicitParamDecl *BlockStructDecl;
ImplicitParamDecl *getBlockStructDecl() { return BlockStructDecl; }
@@ -148,6 +158,8 @@
llvm::Value *BuildCopyHelper(int flag);
llvm::Value *BuildDestroyHelper(int flag);
+ llvm::Value *getBlockObjectDispose();
+ void BuildBlockRelease(const VarDecl &D, llvm::Value *DeclPtr);
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 9cdb40b..a01aad6 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -227,6 +227,7 @@
void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
QualType Ty = D.getType();
bool isByRef = D.getAttr<BlocksAttr>();
+ bool needsDispose = false;
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
@@ -371,6 +372,7 @@
Builder.CreateStore(BuildDestroyHelper(flag), destroy_helper);
}
+ needsDispose = true;
}
// Handle the cleanup attribute
@@ -388,6 +390,11 @@
EmitCall(CGM.getTypes().getFunctionInfo(FD), F, Args);
}
+
+ if (needsDispose) {
+ CleanupScope scope(*this);
+ BuildBlockRelease(D, DeclPtr);
+ }
}
/// Emit an alloca (or GlobalValue depending on target)
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 0e9bf1a..b8e0102 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -24,7 +24,7 @@
using namespace CodeGen;
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
- : BlockFunction(Builder), CGM(cgm), Target(CGM.getContext().Target),
+ : BlockFunction(cgm, Builder), CGM(cgm), Target(CGM.getContext().Target),
DebugInfo(0), SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0) {
LLVMIntTy = ConvertType(getContext().IntTy);
LLVMPointerWidth = Target.getPointerWidth(0);
diff --git a/test/CodeGen/blocks-1.c b/test/CodeGen/blocks-1.c
index 725d71f..c397185 100644
--- a/test/CodeGen/blocks-1.c
+++ b/test/CodeGen/blocks-1.c
@@ -1,4 +1,5 @@
-// RUN: clang %s -emit-llvm -o %t -fblocks -f__block
+// RUN: clang %s -emit-llvm -o %t -fblocks -f__block &&
+// RUN: grep "_Block_object_dispose" %t | count 3
#include <stdio.h>
void test1() {