diff options
author | Antonio Frighetto <me@antoniofrighetto.com> | 2023-12-29 00:25:23 +0100 |
---|---|---|
committer | Antonio Frighetto <me@antoniofrighetto.com> | 2024-02-12 14:17:02 +0100 |
commit | 8373ceef8f2ee377d6daf884e2f3ea11408a7fe2 (patch) | |
tree | 9b55610f49a22069495c982313fe5e046aa7aec9 /llvm/lib/CodeGen/CodeGenPrepare.cpp | |
parent | d1c481d27db07acb6fa68a244bb110bd7ad57a05 (diff) | |
download | llvm-8373ceef8f2ee377d6daf884e2f3ea11408a7fe2.zip llvm-8373ceef8f2ee377d6daf884e2f3ea11408a7fe2.tar.gz llvm-8373ceef8f2ee377d6daf884e2f3ea11408a7fe2.tar.bz2 |
[CGP] Extend `dupRetToEnableTailCallOpts` to known intrinsics
Hint further tail call optimization opportunities when the examined
returned value is the return value of a known intrinsic or library
function, and it appears as first function argument.
Fixes: https://github.com/llvm/llvm-project/issues/75455.
Diffstat (limited to 'llvm/lib/CodeGen/CodeGenPrepare.cpp')
-rw-r--r-- | llvm/lib/CodeGen/CodeGenPrepare.cpp | 70 |
1 files changed, 64 insertions, 6 deletions
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp index 09c4922..32a25b4 100644 --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -2522,8 +2522,40 @@ bool CodeGenPrepare::optimizeCallInst(CallInst *CI, ModifyDT &ModifiedDT) { return false; } +static bool isIntrinsicOrLFToBeTailCalled(const TargetLibraryInfo *TLInfo, + const CallInst *CI) { + assert(CI && CI->use_empty()); + + if (const auto *II = dyn_cast<IntrinsicInst>(CI)) + switch (II->getIntrinsicID()) { + case Intrinsic::memset: + case Intrinsic::memcpy: + case Intrinsic::memmove: + return true; + default: + return false; + } + + LibFunc LF; + Function *Callee = CI->getCalledFunction(); + if (Callee && TLInfo && TLInfo->getLibFunc(*Callee, LF)) + switch (LF) { + case LibFunc_strcpy: + case LibFunc_strncpy: + case LibFunc_strcat: + case LibFunc_strncat: + return true; + default: + return false; + } + + return false; +} + /// Look for opportunities to duplicate return instructions to the predecessor -/// to enable tail call optimizations. The case it is currently looking for is: +/// to enable tail call optimizations. The case it is currently looking for is +/// the following one. Known intrinsics or library function that may be tail +/// called are taken into account as well. /// @code /// bb0: /// %tmp0 = tail call i32 @f0() @@ -2580,8 +2612,6 @@ bool CodeGenPrepare::dupRetToEnableTailCallOpts(BasicBlock *BB, } PN = dyn_cast<PHINode>(V); - if (!PN) - return false; } if (PN && PN->getParent() != BB) @@ -2620,8 +2650,30 @@ bool CodeGenPrepare::dupRetToEnableTailCallOpts(BasicBlock *BB, // Make sure the phi value is indeed produced by the tail call. if (CI && CI->hasOneUse() && CI->getParent() == PredBB && TLI->mayBeEmittedAsTailCall(CI) && - attributesPermitTailCall(F, CI, RetI, *TLI)) + attributesPermitTailCall(F, CI, RetI, *TLI)) { TailCallBBs.push_back(PredBB); + } else { + // Consider the cases in which the phi value is indirectly produced by + // the tail call, for example when encountering memset(), memmove(), + // strcpy(), whose return value may have been optimized out. In such + // cases, the value needs to be the first function argument. + // + // bb0: + // tail call void @llvm.memset.p0.i64(ptr %0, i8 0, i64 %1) + // br label %return + // return: + // %phi = phi ptr [ %0, %bb0 ], [ %2, %entry ] + if (PredBB && PredBB->getSingleSuccessor() == BB) + CI = dyn_cast_or_null<CallInst>( + PredBB->getTerminator()->getPrevNonDebugInstruction(true)); + + if (CI && CI->use_empty() && + isIntrinsicOrLFToBeTailCalled(TLInfo, CI) && + IncomingVal == CI->getArgOperand(0) && + TLI->mayBeEmittedAsTailCall(CI) && + attributesPermitTailCall(F, CI, RetI, *TLI)) + TailCallBBs.push_back(PredBB); + } } } else { SmallPtrSet<BasicBlock *, 4> VisitedBBs; @@ -2631,8 +2683,14 @@ bool CodeGenPrepare::dupRetToEnableTailCallOpts(BasicBlock *BB, if (Instruction *I = Pred->rbegin()->getPrevNonDebugInstruction(true)) { CallInst *CI = dyn_cast<CallInst>(I); if (CI && CI->use_empty() && TLI->mayBeEmittedAsTailCall(CI) && - attributesPermitTailCall(F, CI, RetI, *TLI)) - TailCallBBs.push_back(Pred); + attributesPermitTailCall(F, CI, RetI, *TLI)) { + // Either we return void or the return value must be the first + // argument of a known intrinsic or library function. + if (!V || (isIntrinsicOrLFToBeTailCalled(TLInfo, CI) && + V == CI->getArgOperand(0))) { + TailCallBBs.push_back(Pred); + } + } } } } |