forked from OSchip/llvm-project
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:
parent
05de0298d2
commit
ff61303bd0
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
Loading…
Reference in New Issue