aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2010-07-16 00:00:19 +0000
committerDaniel Dunbar <daniel@zuster.org>2010-07-16 00:00:19 +0000
commit754b9fbaa13749c61393cc613eec7c79efe60ddf (patch)
tree976a999d6480d8ae25cbc7548ed248a81c6a8824
parent673431a2986f750b4d8fadb57abf3f00db27bbbd (diff)
IRgen: Support user defined attributes on block runtime functions.
- This issue here is that /usr/include/Blocks.h wants to define some of the block runtime globals as weak, depending on the target. This doesn't work in Clang because we aren't using the AST decl for these globals. - The fix is a pretty gross hack which just watches all the decls for the specific blocks globals we need to know about; if we see one we use it, otherwise we use the hand coded type. In time, I would like to clean this up by changing IRgen to ask Sema/AST for the decl, which would then be lazily loaded from the builtin table if necessary. This could be used in a whole host of places in IRgen and would get rid of a lot of grotty hand coding of LLVM IR; however, we need some extra Sema support for this as well as support for builtin global variables. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108482 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/Builtins.def5
-rw-r--r--lib/CodeGen/CodeGenModule.cpp55
-rw-r--r--lib/CodeGen/CodeGenModule.h5
-rw-r--r--test/CodeGen/block-decl-merging.c20
4 files changed, 85 insertions, 0 deletions
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index eff4f5e672..44b7f117d4 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -560,5 +560,10 @@ LIBBUILTIN(cos, "dd", "fe", "math.h")
LIBBUILTIN(cosl, "LdLd", "fe", "math.h")
LIBBUILTIN(cosf, "ff", "fe", "math.h")
+// Blocks runtime Builtin math library functions
+LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h")
+LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h")
+// FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock.
+
#undef BUILTIN
#undef LIBBUILTIN
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index f05a018e91..f6788c6c30 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -52,7 +52,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
VTables(*this), Runtime(0), ABI(0),
CFConstantStringClassRef(0), NSConstantStringClassRef(0),
VMContext(M.getContext()),
+ NSConcreteGlobalBlockDecl(0), NSConcreteStackBlockDecl(0),
NSConcreteGlobalBlock(0), NSConcreteStackBlock(0),
+ BlockObjectAssignDecl(0), BlockObjectDisposeDecl(0),
BlockObjectAssign(0), BlockObjectDispose(0){
if (!Features.ObjC1)
@@ -775,6 +777,15 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
// Ignore declarations, they will be emitted on their first use.
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) {
+ if (FD->getIdentifier()) {
+ llvm::StringRef Name = FD->getName();
+ if (Name == "_Block_object_assign") {
+ BlockObjectAssignDecl = FD;
+ } else if (Name == "_Block_object_dispose") {
+ BlockObjectDisposeDecl = FD;
+ }
+ }
+
// Forward declarations are emitted lazily on first use.
if (!FD->isThisDeclarationADefinition())
return;
@@ -782,6 +793,16 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
const VarDecl *VD = cast<VarDecl>(Global);
assert(VD->isFileVarDecl() && "Cannot emit local var decl as global.");
+ if (VD->getIdentifier()) {
+ llvm::StringRef Name = VD->getName();
+ if (Name == "_NSConcreteGlobalBlock") {
+ NSConcreteGlobalBlockDecl = VD;
+ } else if (Name == "_NSConcreteStackBlock") {
+ NSConcreteStackBlockDecl = VD;
+ }
+ }
+
+
if (VD->isThisDeclarationADefinition() != VarDecl::Definition)
return;
}
@@ -2144,6 +2165,14 @@ llvm::Constant *CodeGenModule::getBlockObjectDispose() {
if (BlockObjectDispose)
return BlockObjectDispose;
+ // If we saw an explicit decl, use that.
+ if (BlockObjectDisposeDecl) {
+ return BlockObjectDispose = GetAddrOfFunction(
+ BlockObjectDisposeDecl,
+ getTypes().GetFunctionType(BlockObjectDisposeDecl));
+ }
+
+ // Otherwise construct the function by hand.
const llvm::FunctionType *FTy;
std::vector<const llvm::Type*> ArgTys;
const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
@@ -2158,6 +2187,14 @@ llvm::Constant *CodeGenModule::getBlockObjectAssign() {
if (BlockObjectAssign)
return BlockObjectAssign;
+ // If we saw an explicit decl, use that.
+ if (BlockObjectAssignDecl) {
+ return BlockObjectAssign = GetAddrOfFunction(
+ BlockObjectAssignDecl,
+ getTypes().GetFunctionType(BlockObjectAssignDecl));
+ }
+
+ // Otherwise construct the function by hand.
const llvm::FunctionType *FTy;
std::vector<const llvm::Type*> ArgTys;
const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
@@ -2172,6 +2209,15 @@ llvm::Constant *CodeGenModule::getBlockObjectAssign() {
llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() {
if (NSConcreteGlobalBlock)
return NSConcreteGlobalBlock;
+
+ // If we saw an explicit decl, use that.
+ if (NSConcreteGlobalBlockDecl) {
+ return NSConcreteGlobalBlock = GetAddrOfGlobalVar(
+ NSConcreteGlobalBlockDecl,
+ getTypes().ConvertType(NSConcreteGlobalBlockDecl->getType()));
+ }
+
+ // Otherwise construct the variable by hand.
return NSConcreteGlobalBlock = CreateRuntimeVariable(
PtrToInt8Ty, "_NSConcreteGlobalBlock");
}
@@ -2179,6 +2225,15 @@ llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() {
llvm::Constant *CodeGenModule::getNSConcreteStackBlock() {
if (NSConcreteStackBlock)
return NSConcreteStackBlock;
+
+ // If we saw an explicit decl, use that.
+ if (NSConcreteStackBlockDecl) {
+ return NSConcreteStackBlock = GetAddrOfGlobalVar(
+ NSConcreteStackBlockDecl,
+ getTypes().ConvertType(NSConcreteStackBlockDecl->getType()));
+ }
+
+ // Otherwise construct the variable by hand.
return NSConcreteStackBlock = CreateRuntimeVariable(
PtrToInt8Ty, "_NSConcreteStackBlock");
}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index f3bd307129..420900acdf 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -197,8 +197,13 @@ class CodeGenModule : public BlockModule {
/// @name Cache for Blocks Runtime Globals
/// @{
+ const VarDecl *NSConcreteGlobalBlockDecl;
+ const VarDecl *NSConcreteStackBlockDecl;
llvm::Constant *NSConcreteGlobalBlock;
llvm::Constant *NSConcreteStackBlock;
+
+ const FunctionDecl *BlockObjectAssignDecl;
+ const FunctionDecl *BlockObjectDisposeDecl;
llvm::Constant *BlockObjectAssign;
llvm::Constant *BlockObjectDispose;
diff --git a/test/CodeGen/block-decl-merging.c b/test/CodeGen/block-decl-merging.c
new file mode 100644
index 0000000000..5a3d95b827
--- /dev/null
+++ b/test/CodeGen/block-decl-merging.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -fblocks -emit-llvm -o - %s | \
+// RUN: FileCheck %s
+
+// CHECK: @_NSConcreteGlobalBlock = extern_weak global
+extern void * _NSConcreteStackBlock[32] __attribute__((weak_import));
+// CHECK: @_NSConcreteStackBlock = extern_weak global
+extern void * _NSConcreteGlobalBlock[32] __attribute__((weak_import));
+// CHECK: declare extern_weak void @_Block_object_dispose
+extern void _Block_object_dispose(const void *, const int) __attribute__((weak_import));
+// CHECK: declare extern_weak void @_Block_object_assign
+extern void _Block_object_assign(void *, const void *, const int) __attribute__((weak_import));
+
+void *x = ^(){};
+
+void f1(void (^a0)(void));
+
+void f0() {
+ __block int x;
+ f1(^(void){ x = 1; });
+}