diff options
author | Pete Cooper <peter_cooper@apple.com> | 2016-03-16 00:33:21 +0000 |
---|---|---|
committer | Pete Cooper <peter_cooper@apple.com> | 2016-03-16 00:33:21 +0000 |
commit | be6c750a8ed11b3c165593c761137901d7730117 (patch) | |
tree | a0ea90b3311f0bb247ca2ae0eb92dfeea4cf2600 /clang/lib/CodeGen/CGObjC.cpp | |
parent | f7cb16f7de3f12674e50f3bccdc6842103560b9b (diff) | |
download | bcm5719-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.cpp | 111 |
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) { |