Index: llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp =================================================================== --- llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp +++ llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp @@ -547,13 +547,13 @@ // Don't use GetArgRCIdentityRoot because we don't want to look through bitcasts // and such; to do the replacement, the argument must have type i8*. - Value *Arg = cast(Inst)->getArgOperand(0); - // TODO: Change this to a do-while. - for (;;) { + // Function for replacing uses of Arg dominated by Inst. + auto ReplaceArgUses = [Inst, this](Value *Arg) { // If we're compiling bugpointed code, don't get in trouble. if (!isa(Arg) && !isa(Arg)) - break; + return; + // Look through the uses of the pointer. for (Value::use_iterator UI = Arg->use_begin(), UE = Arg->use_end(); UI != UE; ) { @@ -598,6 +598,14 @@ } } } + }; + + + Value *Arg = cast(Inst)->getArgOperand(0), *OrigArg = Arg; + + // TODO: Change this to a do-while. + for (;;) { + ReplaceArgUses(Arg); // If Arg is a no-op casted pointer, strip one level of casts and iterate. if (const BitCastInst *BI = dyn_cast(Arg)) @@ -611,6 +619,24 @@ else break; } + + // Replace bitcast users of Arg that are dominated by Inst. + SmallVector BitCastUsers; + + // Add all bitcast users of the function argument first. + for (User *U : OrigArg->users()) + if (auto *BC = dyn_cast(U)) + BitCastUsers.push_back(BC); + + // Replace the bitcasts with the call return. Iterate until list is empty. + while (!BitCastUsers.empty()) { + auto *BC = BitCastUsers.pop_back_val(); + for (User *U : BC->users()) + if (auto *B = dyn_cast(U)) + BitCastUsers.push_back(B); + + ReplaceArgUses(BC); + } } // If this function has no escaping allocas or suspicious vararg usage, Index: llvm/trunk/test/Transforms/ObjCARC/contract-replace-arg-use.ll =================================================================== --- llvm/trunk/test/Transforms/ObjCARC/contract-replace-arg-use.ll +++ llvm/trunk/test/Transforms/ObjCARC/contract-replace-arg-use.ll @@ -0,0 +1,18 @@ +; RUN: opt -objc-arc-contract -S < %s | FileCheck %s + +declare i8* @objc_autoreleaseReturnValue(i8*) +declare i8* @foo1() + +; Check that ARC contraction replaces the function return with the value +; returned by @objc_autoreleaseReturnValue. + +; CHECK: %[[V0:[0-9]+]] = tail call i8* @objc_autoreleaseReturnValue( +; CHECK: %[[V1:[0-9]+]] = bitcast i8* %[[V0]] to i32* +; CHECK: ret i32* %[[V1]] + +define i32* @autoreleaseRVTailCall() { + %1 = call i8* @foo1() + %2 = bitcast i8* %1 to i32* + %3 = tail call i8* @objc_autoreleaseReturnValue(i8* %1) + ret i32* %2 +}