summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGObjC.cpp
diff options
context:
space:
mode:
authorPete Cooper <peter_cooper@apple.com>2016-03-16 00:33:21 +0000
committerPete Cooper <peter_cooper@apple.com>2016-03-16 00:33:21 +0000
commitbe6c750a8ed11b3c165593c761137901d7730117 (patch)
treea0ea90b3311f0bb247ca2ae0eb92dfeea4cf2600 /clang/lib/CodeGen/CGObjC.cpp
parentf7cb16f7de3f12674e50f3bccdc6842103560b9b (diff)
downloadbcm5719-llvm-be6c750a8ed11b3c165593c761137901d7730117.tar.gz
bcm5719-llvm-be6c750a8ed11b3c165593c761137901d7730117.zip
Convert some ObjC msgSends to runtime calls.
It is faster to directly call the ObjC runtime for methods such as retain/release instead of sending a message to those functions. This patch adds support for converting messages to retain/release/alloc/autorelease to their equivalent runtime calls. Tests included for the positive case of applying this transformation, negative tests that we ensure we only convert "alloc" to objc_alloc, not "alloc2", and also a driver test to ensure we enable this only for supported runtime versions. Reviewed by John McCall. Differential Revision: http://reviews.llvm.org/D14737 llvm-svn: 263607
Diffstat (limited to 'clang/lib/CodeGen/CGObjC.cpp')
-rw-r--r--clang/lib/CodeGen/CGObjC.cpp111
1 files changed, 96 insertions, 15 deletions
diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp
index 1c165594612..95fdc69cce4 100644
--- a/clang/lib/CodeGen/CGObjC.cpp
+++ b/clang/lib/CodeGen/CGObjC.cpp
@@ -338,6 +338,69 @@ static const Expr *findWeakLValue(const Expr *E) {
return nullptr;
}
+/// The ObjC runtime may provide entrypoints that are likely to be faster
+/// than an ordinary message send of the appropriate selector.
+///
+/// The entrypoints are guaranteed to be equivalent to just sending the
+/// corresponding message. If the entrypoint is implemented naively as just a
+/// message send, using it is a trade-off: it sacrifices a few cycles of
+/// overhead to save a small amount of code. However, it's possible for
+/// runtimes to detect and special-case classes that use "standard"
+/// retain/release behavior; if that's dynamically a large proportion of all
+/// retained objects, using the entrypoint will also be faster than using a
+/// message send.
+///
+/// If the runtime does support a required entrypoint, then this method will
+/// generate a call and return the resulting value. Otherwise it will return
+/// None and the caller can generate a msgSend instead.
+static Optional<llvm::Value *>
+tryGenerateSpecializedMessageSend(CodeGenFunction &CGF, QualType ResultType,
+ llvm::Value *Receiver, Selector Sel,
+ const ObjCMethodDecl *method) {
+ auto &CGM = CGF.CGM;
+ if (!CGM.getCodeGenOpts().ObjCConvertMessagesToRuntimeCalls)
+ return None;
+
+ auto &Runtime = CGM.getLangOpts().ObjCRuntime;
+ switch (Sel.getMethodFamily()) {
+ case OMF_alloc:
+ // Make sure the name is exactly 'alloc'. All methods with that
+ // prefix are identified as OMF_alloc but we only want to call the
+ // runtime for this version.
+ if (Runtime.shouldUseRuntimeFunctionsForAlloc() && Sel.isUnarySelector() &&
+ Sel.getNameForSlot(0) == "alloc" &&
+ ResultType->isObjCObjectPointerType())
+ return CGF.EmitObjCAlloc(Receiver, CGF.ConvertType(ResultType));
+ break;
+
+ case OMF_autorelease:
+ if (ResultType->isObjCObjectPointerType() &&
+ CGM.getLangOpts().getGC() == LangOptions::NonGC &&
+ Runtime.shouldUseARCFunctionsForRetainRelease())
+ return CGF.EmitARCAutorelease(Receiver, CGF.ConvertType(ResultType));
+ break;
+
+ case OMF_retain:
+ if (ResultType->isObjCObjectPointerType() &&
+ CGM.getLangOpts().getGC() == LangOptions::NonGC &&
+ Runtime.shouldUseARCFunctionsForRetainRelease())
+ return CGF.EmitARCRetainNonBlock(Receiver, CGF.ConvertType(ResultType));
+ break;
+
+ case OMF_release:
+ if (ResultType->isVoidType() &&
+ CGM.getLangOpts().getGC() == LangOptions::NonGC &&
+ Runtime.shouldUseARCFunctionsForRetainRelease()) {
+ CGF.EmitARCRelease(Receiver, ARCPreciseLifetime);
+ return nullptr;
+ }
+ break;
+ default:
+ break;
+ }
+ return None;
+}
+
RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReturnValueSlot Return) {
// Only the lookup mechanism and first two arguments of the method
@@ -460,10 +523,16 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
Args,
method);
} else {
- result = Runtime.GenerateMessageSend(*this, Return, ResultType,
- E->getSelector(),
- Receiver, Args, OID,
- method);
+ // Call runtime methods directly if we can.
+ if (Optional<llvm::Value *> SpecializedResult =
+ tryGenerateSpecializedMessageSend(*this, ResultType, Receiver,
+ E->getSelector(), method)) {
+ result = RValue::get(SpecializedResult.getValue());
+ } else {
+ result = Runtime.GenerateMessageSend(*this, Return, ResultType,
+ E->getSelector(), Receiver, Args,
+ OID, method);
+ }
}
// For delegate init calls in ARC, implicitly store the result of
@@ -1814,6 +1883,7 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
/// where a null input causes a no-op and returns null.
static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
llvm::Value *value,
+ llvm::Type *returnType,
llvm::Constant *&fn,
StringRef fnName,
bool isTailCall = false) {
@@ -1826,7 +1896,7 @@ static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
}
// Cast the argument to 'id'.
- llvm::Type *origType = value->getType();
+ llvm::Type *origType = returnType ? returnType : value->getType();
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
// Call the function.
@@ -1931,8 +2001,9 @@ llvm::Value *CodeGenFunction::EmitARCRetain(QualType type, llvm::Value *value) {
/// Retain the given object, with normal retain semantics.
/// call i8* \@objc_retain(i8* %value)
-llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value) {
- return emitARCValueOperation(*this, value,
+llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value,
+ llvm::Type *returnType) {
+ return emitARCValueOperation(*this, value, returnType,
CGM.getObjCEntrypoints().objc_retain,
"objc_retain");
}
@@ -1946,7 +2017,7 @@ llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value) {
llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value,
bool mandatory) {
llvm::Value *result
- = emitARCValueOperation(*this, value,
+ = emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retainBlock,
"objc_retainBlock");
@@ -2016,7 +2087,7 @@ static void emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
emitAutoreleasedReturnValueMarker(*this);
- return emitARCValueOperation(*this, value,
+ return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retainAutoreleasedReturnValue,
"objc_retainAutoreleasedReturnValue");
}
@@ -2031,7 +2102,7 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
llvm::Value *
CodeGenFunction::EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value) {
emitAutoreleasedReturnValueMarker(*this);
- return emitARCValueOperation(*this, value,
+ return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_unsafeClaimAutoreleasedReturnValue,
"objc_unsafeClaimAutoreleasedReturnValue");
}
@@ -2145,8 +2216,9 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst,
/// Autorelease the given object.
/// call i8* \@objc_autorelease(i8* %value)
-llvm::Value *CodeGenFunction::EmitARCAutorelease(llvm::Value *value) {
- return emitARCValueOperation(*this, value,
+llvm::Value *CodeGenFunction::EmitARCAutorelease(llvm::Value *value,
+ llvm::Type *resultType) {
+ return emitARCValueOperation(*this, value, resultType,
CGM.getObjCEntrypoints().objc_autorelease,
"objc_autorelease");
}
@@ -2155,7 +2227,7 @@ llvm::Value *CodeGenFunction::EmitARCAutorelease(llvm::Value *value) {
/// call i8* \@objc_autoreleaseReturnValue(i8* %value)
llvm::Value *
CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) {
- return emitARCValueOperation(*this, value,
+ return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_autoreleaseReturnValue,
"objc_autoreleaseReturnValue",
/*isTailCall*/ true);
@@ -2165,7 +2237,7 @@ CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) {
/// call i8* \@objc_retainAutoreleaseReturnValue(i8* %value)
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseReturnValue(llvm::Value *value) {
- return emitARCValueOperation(*this, value,
+ return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retainAutoreleaseReturnValue,
"objc_retainAutoreleaseReturnValue",
/*isTailCall*/ true);
@@ -2194,7 +2266,7 @@ llvm::Value *CodeGenFunction::EmitARCRetainAutorelease(QualType type,
/// call i8* \@objc_retainAutorelease(i8* %value)
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseNonBlock(llvm::Value *value) {
- return emitARCValueOperation(*this, value,
+ return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retainAutorelease,
"objc_retainAutorelease");
}
@@ -2338,6 +2410,15 @@ llvm::Value *CodeGenFunction::EmitObjCMRRAutoreleasePoolPush() {
return InitRV.getScalarVal();
}
+/// Allocate the given objc object.
+/// call i8* \@objc_alloc(i8* %value)
+llvm::Value *CodeGenFunction::EmitObjCAlloc(llvm::Value *value,
+ llvm::Type *resultType) {
+ return emitARCValueOperation(*this, value, resultType,
+ CGM.getObjCEntrypoints().objc_alloc,
+ "objc_alloc");
+}
+
/// Produce the code to do a primitive release.
/// [tmp drain];
void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
OpenPOWER on IntegriCloud