Mark calls to objc_retainBlock that don't result from casts

to id so that we can still optimize them appropriately.

llvm-svn: 141064
This commit is contained in:
John McCall 2011-10-04 06:23:45 +00:00
parent 05de0298d2
commit ff61303bd0
4 changed files with 74 additions and 13 deletions

View File

@ -1128,10 +1128,8 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
value = CGF.EmitARCRetainAutoreleasedReturnValue(value); value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
return CGF.EmitObjCConsumeObject(E->getType(), value); return CGF.EmitObjCConsumeObject(E->getType(), value);
} }
case CK_ARCExtendBlockObject: { case CK_ARCExtendBlockObject:
llvm::Value *value = CGF.EmitARCRetainScalarExpr(E); return CGF.EmitARCExtendBlockObject(E);
return CGF.EmitObjCConsumeObject(E->getType(), value);
}
case CK_FloatingRealToComplex: case CK_FloatingRealToComplex:
case CK_FloatingComplexCast: case CK_FloatingComplexCast:

View File

@ -1658,7 +1658,7 @@ static void emitARCCopyOperation(CodeGenFunction &CGF,
/// call i8* @objc_retainBlock(i8* %value) /// call i8* @objc_retainBlock(i8* %value)
llvm::Value *CodeGenFunction::EmitARCRetain(QualType type, llvm::Value *value) { llvm::Value *CodeGenFunction::EmitARCRetain(QualType type, llvm::Value *value) {
if (type->isBlockPointerType()) if (type->isBlockPointerType())
return EmitARCRetainBlock(value); return EmitARCRetainBlock(value, /*mandatory*/ false);
else else
return EmitARCRetainNonBlock(value); return EmitARCRetainNonBlock(value);
} }
@ -1673,10 +1673,32 @@ llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value) {
/// Retain the given block, with _Block_copy semantics. /// Retain the given block, with _Block_copy semantics.
/// call i8* @objc_retainBlock(i8* %value) /// call i8* @objc_retainBlock(i8* %value)
llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value) { ///
return emitARCValueOperation(*this, value, /// \param mandatory - If false, emit the call with metadata
CGM.getARCEntrypoints().objc_retainBlock, /// indicating that it's okay for the optimizer to eliminate this call
"objc_retainBlock"); /// if it can prove that the block never escapes except down the stack.
llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value,
bool mandatory) {
llvm::Value *result
= emitARCValueOperation(*this, value,
CGM.getARCEntrypoints().objc_retainBlock,
"objc_retainBlock");
// If the copy isn't mandatory, add !clang.arc.copy_on_escape to
// tell the optimizer that it doesn't need to do this copy if the
// block doesn't escape, where being passed as an argument doesn't
// count as escaping.
if (!mandatory && isa<llvm::Instruction>(result)) {
llvm::CallInst *call
= cast<llvm::CallInst>(result->stripPointerCasts());
assert(call->getCalledValue() == CGM.getARCEntrypoints().objc_retainBlock);
SmallVector<llvm::Value*,1> args;
call->setMetadata("clang.arc.copy_on_escape",
llvm::MDNode::get(Builder.getContext(), args));
}
return result;
} }
/// Retain the given object which is the result of a function call. /// Retain the given object which is the result of a function call.
@ -1857,7 +1879,7 @@ llvm::Value *CodeGenFunction::EmitARCRetainAutorelease(QualType type,
llvm::Type *origType = value->getType(); llvm::Type *origType = value->getType();
value = Builder.CreateBitCast(value, Int8PtrTy); value = Builder.CreateBitCast(value, Int8PtrTy);
value = EmitARCRetainBlock(value); value = EmitARCRetainBlock(value, /*mandatory*/ true);
value = EmitARCAutorelease(value); value = EmitARCAutorelease(value);
return Builder.CreateBitCast(value, origType); return Builder.CreateBitCast(value, origType);
} }
@ -2300,7 +2322,7 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
} }
// Retain the object as a block, then cast down. // Retain the object as a block, then cast down.
result = CGF.EmitARCRetainBlock(result); result = CGF.EmitARCRetainBlock(result, /*mandatory*/ true);
if (resultType) result = CGF.Builder.CreateBitCast(result, resultType); if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
return TryEmitResult(result, true); return TryEmitResult(result, true);
} }
@ -2386,6 +2408,24 @@ CodeGenFunction::EmitARCRetainAutoreleaseScalarExpr(const Expr *e) {
return value; return value;
} }
llvm::Value *CodeGenFunction::EmitARCExtendBlockObject(const Expr *e) {
llvm::Value *result;
bool doRetain;
if (shouldEmitSeparateBlockRetain(e)) {
result = EmitScalarExpr(e);
doRetain = true;
} else {
TryEmitResult subresult = tryEmitARCRetainScalarExpr(*this, e);
result = subresult.getPointer();
doRetain = !subresult.getInt();
}
if (doRetain)
result = EmitARCRetainBlock(result, /*mandatory*/ true);
return EmitObjCConsumeObject(e->getType(), result);
}
llvm::Value *CodeGenFunction::EmitObjCThrowOperand(const Expr *expr) { llvm::Value *CodeGenFunction::EmitObjCThrowOperand(const Expr *expr) {
// In ARC, retain and autorelease the expression. // In ARC, retain and autorelease the expression.
if (getLangOptions().ObjCAutoRefCount) { if (getLangOptions().ObjCAutoRefCount) {
@ -2423,7 +2463,7 @@ CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
// type, then we need to emit the block-retain immediately in case // type, then we need to emit the block-retain immediately in case
// it invalidates the l-value. // it invalidates the l-value.
if (!hasImmediateRetain && e->getType()->isBlockPointerType()) { if (!hasImmediateRetain && e->getType()->isBlockPointerType()) {
value = EmitARCRetainBlock(value); value = EmitARCRetainBlock(value, /*mandatory*/ false);
hasImmediateRetain = true; hasImmediateRetain = true;
} }

View File

@ -2129,7 +2129,7 @@ public:
bool ignored); bool ignored);
llvm::Value *EmitARCRetain(QualType type, llvm::Value *value); llvm::Value *EmitARCRetain(QualType type, llvm::Value *value);
llvm::Value *EmitARCRetainNonBlock(llvm::Value *value); llvm::Value *EmitARCRetainNonBlock(llvm::Value *value);
llvm::Value *EmitARCRetainBlock(llvm::Value *value); llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory);
void EmitARCRelease(llvm::Value *value, bool precise); void EmitARCRelease(llvm::Value *value, bool precise);
llvm::Value *EmitARCAutorelease(llvm::Value *value); llvm::Value *EmitARCAutorelease(llvm::Value *value);
llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value); llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
@ -2147,6 +2147,7 @@ public:
llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr); llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr);
llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr); llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr);
llvm::Value *EmitARCExtendBlockObject(const Expr *expr);
llvm::Value *EmitARCRetainScalarExpr(const Expr *expr); llvm::Value *EmitARCRetainScalarExpr(const Expr *expr);
llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr); llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr);

View File

@ -0,0 +1,22 @@
// RUN: %clang_cc1 -fobjc-arc -fblocks -emit-llvm %s -o - | FileCheck %s
typedef void (^block_t)(void);
void use_block(block_t);
void use_int(int);
// rdar://problem/10211676
void test0(int i) {
block_t block = ^{ use_int(i); };
// CHECK: define void @test0(
// CHECK: call i8* @objc_retainBlock(i8* {{%.*}}) nounwind, !clang.arc.copy_on_escape
// CHECK: ret void
}
void test1(int i) {
id block = ^{ use_int(i); };
// CHECK: define void @test1(
// CHECK: call i8* @objc_retainBlock(i8* {{%.*}}) nounwind
// CHECK-NOT: !clang.arc.copy_on_escape
// CHECK: ret void
}