diff --git a/llvm/lib/CodeGen/Analysis.cpp b/llvm/lib/CodeGen/Analysis.cpp --- a/llvm/lib/CodeGen/Analysis.cpp +++ b/llvm/lib/CodeGen/Analysis.cpp @@ -611,6 +611,22 @@ return CallerAttrs == CalleeAttrs; } +/// Check whether B is a bitcast of a pointer type to another pointer type, +/// which is equal to A. +static bool isPointerBitcastEqualTo(const Value *A, const Value *B) { + assert(A && B && "Expected non-null inputs!"); + + auto *BitCastIn = dyn_cast(B); + + if (!BitCastIn) + return false; + + if (!A->getType()->isPointerTy() || !B->getType()->isPointerTy()) + return false; + + return A == BitCastIn->getOperand(0); +} + bool llvm::returnTypeIsEligibleForTailCall(const Function *F, const Instruction *I, const ReturnInst *Ret, @@ -643,7 +659,8 @@ TLI.getLibcallName(RTLIB::MEMMOVE) == StringRef("memmove")) || (IID == Intrinsic::memset && TLI.getLibcallName(RTLIB::MEMSET) == StringRef("memset"))) && - RetVal == Call->getArgOperand(0)) + (RetVal == Call->getArgOperand(0) || + isPointerBitcastEqualTo(RetVal, Call->getArgOperand(0)))) return true; } diff --git a/llvm/test/CodeGen/AArch64/tailcall-bitcast-memcpy.ll b/llvm/test/CodeGen/AArch64/tailcall-bitcast-memcpy.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/tailcall-bitcast-memcpy.ll @@ -0,0 +1,18 @@ +;RUN: llc %s -o - -verify-machineinstrs | FileCheck %s +target triple = "aarch64-arm-none-eabi" + +;CHECK-LABEL: @wmemcpy +;CHECK: lsl +;CHECK-NOT: bl +;CHECK-NOT: mov +;CHECK-NOT: ldp +;CHECK-NEXT: b memcpy +define dso_local i32* @wmemcpy(i32* returned, i32* nocapture readonly, i64) local_unnamed_addr { + %4 = bitcast i32* %0 to i8* + %5 = bitcast i32* %1 to i8* + %6 = shl i64 %2, 2 + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %4, i8* align 4 %5, i64 %6, i1 false) + ret i32* %0 +} + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1)