diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h index dc00db9daa3b6..9d43b2435b672 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 9072a0aa1531f..3fe98b367cb01 100644 --- a/llvm/include/llvm/IR/RuntimeLibcalls.td +++ b/llvm/include/llvm/IR/RuntimeLibcalls.td @@ -282,6 +282,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 { @@ -2115,6 +2116,7 @@ defset list PPC64AIXCallList = { def ___memmove64 : RuntimeLibcallImpl; def ___memset64 : RuntimeLibcallImpl; def ___bzero64 : RuntimeLibcallImpl; + def ___strlen64 : RuntimeLibcallImpl; } defset list PPC32AIXCallList = { @@ -2122,6 +2124,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 4b7fc45908119..2b259ef3036d2 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -9050,6 +9050,37 @@ 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. + auto GetEntry = [](Type *Ty, SDValue &SDV) { + TargetLowering::ArgListEntry E; + E.Ty = Ty; + E.Node = SDV; + return E; + }; + + PointerType *PT = PointerType::getUnqual(*getContext()); + TargetLowering::ArgListTy Args = {GetEntry(PT, Src)}; + + TargetLowering::CallLoweringInfo CLI(*this); + + // TODO: propagate tail call flag for targets where that is safe. Note + // that it is not safe on AIX which is the only current target. + CLI.setDebugLoc(dl).setChain(Chain).setLibCallee( + TLI->getLibcallCallingConv(RTLIB::STRLEN), CI->getType(), + getExternalSymbol(LibCallName, TLI->getProgramPointerTy(getDataLayout())), + std::move(Args)); + + 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 366a230eef952..9a75f417e2af8 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -9287,9 +9287,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)