diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h index 8a834315646a1..d9d6f0bcdcb84 100644 --- a/llvm/include/llvm/CodeGen/SelectionDAG.h +++ b/llvm/include/llvm/CodeGen/SelectionDAG.h @@ -1259,6 +1259,9 @@ class SelectionDAG { std::pair getMemcmp(SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, const CallInst *CI); + LLVM_ABI std::pair + getStrlen(SDValue Chain, const SDLoc &dl, SDValue Src, const CallInst *CI); + /* \p CI if not null is the memset call being lowered. * \p OverrideTailCall is an optional parameter that can be used to override * the tail call optimization decision. */ diff --git a/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h b/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h index fd00f813bc9c3..fbfb240cae449 100644 --- a/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h +++ b/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h @@ -162,7 +162,7 @@ class SelectionDAGTargetInfo { virtual std::pair EmitTargetCodeForStrlen(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, - SDValue Src, MachinePointerInfo SrcPtrInfo) const { + SDValue Src, const CallInst *CI) const { return std::make_pair(SDValue(), SDValue()); } diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td index fd0ea3a2332c9..6183a7e2b04db 100644 --- a/llvm/include/llvm/IR/RuntimeLibcalls.td +++ b/llvm/include/llvm/IR/RuntimeLibcalls.td @@ -297,6 +297,7 @@ def MEMMOVE : RuntimeLibcall; def MEMSET : RuntimeLibcall; def CALLOC : RuntimeLibcall; def BZERO : RuntimeLibcall; +def STRLEN : RuntimeLibcall; // Element-wise unordered-atomic memory of different sizes foreach MemSize = [1, 2, 4, 8, 16] in { @@ -2272,6 +2273,7 @@ defset list PPC64AIXCallList = { def ___memmove64 : RuntimeLibcallImpl; def ___memset64 : RuntimeLibcallImpl; def ___bzero64 : RuntimeLibcallImpl; + def ___strlen64 : RuntimeLibcallImpl; } defset list PPC32AIXCallList = { @@ -2279,6 +2281,7 @@ defset list PPC32AIXCallList = { def ___memmove : RuntimeLibcallImpl; def ___memset : RuntimeLibcallImpl; def ___bzero : RuntimeLibcallImpl; + def ___strlen : RuntimeLibcallImpl; } defvar PPCOverrides = !foreach(entry, PPCRuntimeLibcalls, entry.Provides); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 029eb025ff1de..b18d96e79c636 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -9094,6 +9094,33 @@ SelectionDAG::getMemcmp(SDValue Chain, const SDLoc &dl, SDValue Mem0, return TLI->LowerCallTo(CLI); } +std::pair SelectionDAG::getStrlen(SDValue Chain, + const SDLoc &dl, + SDValue Src, + const CallInst *CI) { + const char *LibCallName = TLI->getLibcallName(RTLIB::STRLEN); + if (!LibCallName) + return {}; + + // Emit a library call. + TargetLowering::ArgListTy Args = { + {Src, PointerType::getUnqual(*getContext())}}; + + TargetLowering::CallLoweringInfo CLI(*this); + bool IsTailCall = + isInTailCallPositionWrapper(CI, this, /*AllowReturnsFirstArg*/ true); + + CLI.setDebugLoc(dl) + .setChain(Chain) + .setLibCallee(TLI->getLibcallCallingConv(RTLIB::STRLEN), CI->getType(), + getExternalSymbol( + LibCallName, TLI->getProgramPointerTy(getDataLayout())), + std::move(Args)) + .setTailCall(IsTailCall); + + return TLI->LowerCallTo(CLI); +} + SDValue SelectionDAG::getMemcpy( SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, Align Alignment, bool isVol, bool AlwaysInline, const CallInst *CI, diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 430e47451fd49..1d57d6ed754d4 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -9335,9 +9335,8 @@ bool SelectionDAGBuilder::visitStrLenCall(const CallInst &I) { const Value *Arg0 = I.getArgOperand(0); const SelectionDAGTargetInfo &TSI = DAG.getSelectionDAGInfo(); - std::pair Res = - TSI.EmitTargetCodeForStrlen(DAG, getCurSDLoc(), DAG.getRoot(), - getValue(Arg0), MachinePointerInfo(Arg0)); + std::pair Res = TSI.EmitTargetCodeForStrlen( + DAG, getCurSDLoc(), DAG.getRoot(), getValue(Arg0), &I); if (Res.first.getNode()) { processIntegerCallValue(I, Res.first, false); PendingLoads.push_back(Res.second); diff --git a/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp b/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp index 4039fedd0cb5c..93a4693c50168 100644 --- a/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp +++ b/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp @@ -28,3 +28,10 @@ std::pair PPCSelectionDAGInfo::EmitTargetCodeForMemcmp( SDValue Op3, const CallInst *CI) const { return DAG.getMemcmp(Chain, dl, Op1, Op2, Op3, CI); } + +std::pair +PPCSelectionDAGInfo::EmitTargetCodeForStrlen(SelectionDAG &DAG, const SDLoc &DL, + SDValue Chain, SDValue Src, + const CallInst *CI) const { + return DAG.getStrlen(Chain, DL, Src, CI); +} diff --git a/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.h b/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.h index 1537851a1b610..f962a7a5321aa 100644 --- a/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.h +++ b/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.h @@ -25,6 +25,9 @@ class PPCSelectionDAGInfo : public SelectionDAGTargetInfo { EmitTargetCodeForMemcmp(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Op1, SDValue Op2, SDValue Op3, const CallInst *CI) const override; + std::pair + EmitTargetCodeForStrlen(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, + SDValue Src, const CallInst *CI) const override; }; } // namespace llvm diff --git a/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp b/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp index afe838ac973e6..eb00d484af693 100644 --- a/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp +++ b/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp @@ -263,7 +263,7 @@ static std::pair getBoundedStrlen(SelectionDAG &DAG, std::pair SystemZSelectionDAGInfo::EmitTargetCodeForStrlen( SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Src, - MachinePointerInfo SrcPtrInfo) const { + const CallInst *CI) const { EVT PtrVT = Src.getValueType(); return getBoundedStrlen(DAG, DL, Chain, Src, DAG.getConstant(0, DL, PtrVT)); } diff --git a/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.h b/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.h index 5a1e0cd108e77..200566f9646c1 100644 --- a/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.h +++ b/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.h @@ -61,8 +61,7 @@ class SystemZSelectionDAGInfo : public SelectionDAGTargetInfo { std::pair EmitTargetCodeForStrlen(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, - SDValue Src, - MachinePointerInfo SrcPtrInfo) const override; + SDValue Src, const CallInst *CI) const override; std::pair EmitTargetCodeForStrnlen(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, diff --git a/llvm/test/CodeGen/PowerPC/milicode32.ll b/llvm/test/CodeGen/PowerPC/milicode32.ll index a2af6d413b4bf..78d036202fe4e 100644 --- a/llvm/test/CodeGen/PowerPC/milicode32.ll +++ b/llvm/test/CodeGen/PowerPC/milicode32.ll @@ -42,7 +42,7 @@ define i32 @strlen_test(ptr noundef %str) nounwind { ; CHECK-AIX-32-P9-NEXT: stwu r1, -64(r1) ; CHECK-AIX-32-P9-NEXT: stw r0, 72(r1) ; CHECK-AIX-32-P9-NEXT: stw r3, 60(r1) -; CHECK-AIX-32-P9-NEXT: bl .strlen[PR] +; CHECK-AIX-32-P9-NEXT: bl .___strlen[PR] ; CHECK-AIX-32-P9-NEXT: nop ; CHECK-AIX-32-P9-NEXT: addi r1, r1, 64 ; CHECK-AIX-32-P9-NEXT: lwz r0, 8(r1) diff --git a/llvm/test/CodeGen/PowerPC/milicode64.ll b/llvm/test/CodeGen/PowerPC/milicode64.ll index 0f0585d9028a9..8b87529d9a6d8 100644 --- a/llvm/test/CodeGen/PowerPC/milicode64.ll +++ b/llvm/test/CodeGen/PowerPC/milicode64.ll @@ -85,7 +85,7 @@ define i64 @strlen_test(ptr noundef %str) nounwind { ; CHECK-AIX-64-P9-NEXT: stdu r1, -128(r1) ; CHECK-AIX-64-P9-NEXT: std r0, 144(r1) ; CHECK-AIX-64-P9-NEXT: std r3, 120(r1) -; CHECK-AIX-64-P9-NEXT: bl .strlen[PR] +; CHECK-AIX-64-P9-NEXT: bl .___strlen64[PR] ; CHECK-AIX-64-P9-NEXT: nop ; CHECK-AIX-64-P9-NEXT: addi r1, r1, 128 ; CHECK-AIX-64-P9-NEXT: ld r0, 16(r1)