Index: lib/Transforms/ObjCARC/ObjCARCContract.cpp =================================================================== --- lib/Transforms/ObjCARC/ObjCARCContract.cpp +++ lib/Transforms/ObjCARC/ObjCARCContract.cpp @@ -13,6 +13,10 @@ /// This specific file mainly deals with ``contracting'' multiple lower level /// operations into singular higher level operations through pattern matching. /// +/// This file also replaces uses of the argument of a call to objc_autorelease +/// in MRR with the result to enable performing tall-call optimization on the +/// call when the call result is returned by the calling function. +/// /// WARNING: This file knows about certain library functions. It recognizes them /// by name, and hardwires knowledge of their semantics. /// @@ -535,6 +539,11 @@ Inst->eraseFromParent(); return true; default: + // Replace uses of the argument of a call to objc_autorelease in MRR with + // the result to enable performing tail-call optimization on it. + if (auto *CI = dyn_cast(Inst)) + if (Function *Callee = CI->getCalledFunction()) + return !Callee->getName().equals("objc_autorelease"); return true; } } @@ -767,8 +776,9 @@ Pass *llvm::createObjCARCContractPass() { return new ObjCARCContract(); } bool ObjCARCContract::doInitialization(Module &M) { - // If nothing in the Module uses ARC, don't do anything. - Run = ModuleHasARC(M); + // If nothing in the Module uses ARC or calls objc_autorelease in MRR, don't + // do anything. + Run = ModuleHasARC(M) || M.getNamedValue("objc_autorelease"); if (!Run) return false; Index: test/Transforms/ObjCARC/contract-replace-arg-use.ll =================================================================== --- test/Transforms/ObjCARC/contract-replace-arg-use.ll +++ test/Transforms/ObjCARC/contract-replace-arg-use.ll @@ -1,5 +1,6 @@ ; RUN: opt -objc-arc-contract -S < %s | FileCheck %s +%0 = type opaque declare i8* @llvm.objc.autoreleaseReturnValue(i8*) declare i8* @foo1() @@ -44,3 +45,17 @@ %v4 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %phival) ret i32* %retval } + +; CHECK-LABEL: define %0* @testAutoreleaseTailCallMRR( +; CHECK: %[[V1:.*]] = tail call i8* @objc_autorelease(i8* % +; CHECK: %[[V2:.*]] = bitcast i8* %[[V1]] to %0* +; CHECK: ret %0* %[[V2]] + +define %0* @testAutoreleaseTailCallMRR() { + %call = tail call i8* @foo1() + %v0 = bitcast i8* %call to %0* + %v1 = tail call i8* @objc_autorelease(i8* %call) + ret %0* %v0 +} + +declare i8* @objc_autorelease(i8*)