[llvm] [PowerPC] using milicode call for strlen instead of lib call (PR #153600)
zhijian lin via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 22 11:09:44 PDT 2025
https://github.com/diggerlin updated https://github.com/llvm/llvm-project/pull/153600
>From 9f275a29d5b0236291a1396c1ad0aa809dd77c86 Mon Sep 17 00:00:00 2001
From: zhijian <zhijian at ca.ibm.com>
Date: Wed, 13 Aug 2025 18:25:55 +0000
Subject: [PATCH 1/4] implement using milicode for strlen instead of libcall
---
llvm/include/llvm/CodeGen/SelectionDAG.h | 10 +++--
.../llvm/CodeGen/SelectionDAGTargetInfo.h | 2 +-
llvm/include/llvm/IR/RuntimeLibcalls.td | 3 ++
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 37 +++++++++++++++++++
.../SelectionDAG/SelectionDAGBuilder.cpp | 5 +--
.../Target/PowerPC/PPCSelectionDAGInfo.cpp | 8 ++++
llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.h | 3 ++
.../SystemZ/SystemZSelectionDAGInfo.cpp | 2 +-
.../Target/SystemZ/SystemZSelectionDAGInfo.h | 3 +-
llvm/test/CodeGen/PowerPC/milicode32.ll | 2 +-
llvm/test/CodeGen/PowerPC/milicode64.ll | 3 +-
11 files changed, 66 insertions(+), 12 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index dc00db9daa3b6..831e274b22ec4 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -1256,9 +1256,13 @@ class SelectionDAG {
/// stack arguments from being clobbered.
LLVM_ABI SDValue getStackArgumentTokenFactor(SDValue Chain);
- std::pair<SDValue, SDValue> getMemcmp(SDValue Chain, const SDLoc &dl,
- SDValue Dst, SDValue Src, SDValue Size,
- const CallInst *CI);
+ LLVM_ABI std::pair<SDValue, SDValue> getMemcmp(SDValue Chain, const SDLoc &dl,
+ SDValue Dst, SDValue Src,
+ SDValue Size,
+ const CallInst *CI);
+ LLVM_ABI std::pair<SDValue, SDValue>
+ 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<SDValue, SDValue>
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<RuntimeLibcallImpl> PPC64AIXCallList = {
def ___memmove64 : RuntimeLibcallImpl<MEMCPY>;
def ___memset64 : RuntimeLibcallImpl<MEMSET>;
def ___bzero64 : RuntimeLibcallImpl<BZERO>;
+ def ___strlen64 : RuntimeLibcallImpl<STRLEN>;
}
defset list<RuntimeLibcallImpl> PPC32AIXCallList = {
@@ -2122,6 +2124,7 @@ defset list<RuntimeLibcallImpl> PPC32AIXCallList = {
def ___memmove : RuntimeLibcallImpl<MEMMOVE>;
def ___memset : RuntimeLibcallImpl<MEMSET>;
def ___bzero : RuntimeLibcallImpl<BZERO>;
+ def ___strlen : RuntimeLibcallImpl<STRLEN>;
}
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..61674f9fa55f8 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -9050,6 +9050,43 @@ SelectionDAG::getMemcmp(SDValue Chain, const SDLoc &dl, SDValue Mem0,
return TLI->LowerCallTo(CLI);
}
+std::pair<SDValue, SDValue> 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);
+ bool IsTailCall = false;
+ bool ReturnsFirstArg = CI && funcReturnsFirstArgOfCall(*CI);
+ IsTailCall = CI && CI->isTailCall() &&
+ isInTailCallPosition(*CI, getTarget(), ReturnsFirstArg);
+
+ CLI.setDebugLoc(dl)
+ .setChain(Chain)
+ .setLibCallee(
+ TLI->getLibcallCallingConv(RTLIB::STRLEN),
+ Type::getInt32Ty(*getContext()),
+ getExternalSymbol(LibCallName, TLI->getPointerTy(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 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<SDValue, SDValue> Res =
- TSI.EmitTargetCodeForStrlen(DAG, getCurSDLoc(), DAG.getRoot(),
- getValue(Arg0), MachinePointerInfo(Arg0));
+ std::pair<SDValue, SDValue> 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..e15b5b0bea2fc 100644
--- a/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp
@@ -28,3 +28,11 @@ std::pair<SDValue, SDValue> PPCSelectionDAGInfo::EmitTargetCodeForMemcmp(
SDValue Op3, const CallInst *CI) const {
return DAG.getMemcmp(Chain, dl, Op1, Op2, Op3, CI);
}
+
+std::pair<SDValue, SDValue>
+PPCSelectionDAGInfo::EmitTargetCodeForStrlen(SelectionDAG &DAG, const SDLoc &DL,
+ SDValue Chain, SDValue Src,
+ const CallInst *CI) const {
+ EVT PtrVT = Src.getValueType();
+ 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<SDValue, SDValue>
+ 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<SDValue, SDValue> getBoundedStrlen(SelectionDAG &DAG,
std::pair<SDValue, SDValue> 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<SDValue, SDValue>
EmitTargetCodeForStrlen(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain,
- SDValue Src,
- MachinePointerInfo SrcPtrInfo) const override;
+ SDValue Src, const CallInst *CI) const override;
std::pair<SDValue, SDValue>
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..31d8704b7974c 100644
--- a/llvm/test/CodeGen/PowerPC/milicode64.ll
+++ b/llvm/test/CodeGen/PowerPC/milicode64.ll
@@ -85,8 +85,9 @@ 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: clrldi r3, r3, 32
; CHECK-AIX-64-P9-NEXT: addi r1, r1, 128
; CHECK-AIX-64-P9-NEXT: ld r0, 16(r1)
; CHECK-AIX-64-P9-NEXT: mtlr r0
>From 8ed02ded0bf591edad32488fdead401acd3b1e0f Mon Sep 17 00:00:00 2001
From: zhijian <zhijian at ca.ibm.com>
Date: Thu, 14 Aug 2025 14:06:05 +0000
Subject: [PATCH 2/4] fix an error
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 3 +--
llvm/test/CodeGen/PowerPC/milicode64.ll | 1 -
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 61674f9fa55f8..a1f3a9b201a30 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -9078,8 +9078,7 @@ std::pair<SDValue, SDValue> SelectionDAG::getStrlen(SDValue Chain,
CLI.setDebugLoc(dl)
.setChain(Chain)
.setLibCallee(
- TLI->getLibcallCallingConv(RTLIB::STRLEN),
- Type::getInt32Ty(*getContext()),
+ TLI->getLibcallCallingConv(RTLIB::STRLEN), CI->getType(),
getExternalSymbol(LibCallName, TLI->getPointerTy(getDataLayout())),
std::move(Args))
.setTailCall(IsTailCall);
diff --git a/llvm/test/CodeGen/PowerPC/milicode64.ll b/llvm/test/CodeGen/PowerPC/milicode64.ll
index 31d8704b7974c..8b87529d9a6d8 100644
--- a/llvm/test/CodeGen/PowerPC/milicode64.ll
+++ b/llvm/test/CodeGen/PowerPC/milicode64.ll
@@ -87,7 +87,6 @@ define i64 @strlen_test(ptr noundef %str) nounwind {
; CHECK-AIX-64-P9-NEXT: std r3, 120(r1)
; CHECK-AIX-64-P9-NEXT: bl .___strlen64[PR]
; CHECK-AIX-64-P9-NEXT: nop
-; CHECK-AIX-64-P9-NEXT: clrldi r3, r3, 32
; CHECK-AIX-64-P9-NEXT: addi r1, r1, 128
; CHECK-AIX-64-P9-NEXT: ld r0, 16(r1)
; CHECK-AIX-64-P9-NEXT: mtlr r0
>From 56fa506b61a826267b59ae281dca3115f0c67496 Mon Sep 17 00:00:00 2001
From: zhijian <zhijian at ca.ibm.com>
Date: Wed, 20 Aug 2025 17:47:46 +0000
Subject: [PATCH 3/4] address comment
---
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 26 +++++++++++--------
.../Target/PowerPC/PPCSelectionDAGInfo.cpp | 1 -
2 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index a1f3a9b201a30..a2946736682a6 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -9070,18 +9070,22 @@ std::pair<SDValue, SDValue> SelectionDAG::getStrlen(SDValue Chain,
TargetLowering::ArgListTy Args = {GetEntry(PT, Src)};
TargetLowering::CallLoweringInfo CLI(*this);
- bool IsTailCall = false;
- bool ReturnsFirstArg = CI && funcReturnsFirstArgOfCall(*CI);
- IsTailCall = CI && CI->isTailCall() &&
- isInTailCallPosition(*CI, getTarget(), ReturnsFirstArg);
- CLI.setDebugLoc(dl)
- .setChain(Chain)
- .setLibCallee(
- TLI->getLibcallCallingConv(RTLIB::STRLEN), CI->getType(),
- getExternalSymbol(LibCallName, TLI->getPointerTy(getDataLayout())),
- std::move(Args))
- .setTailCall(IsTailCall);
+ // TODO: Intentionally not marking this libcall as a tail call.
+ //
+ // Why:
+ // - The only current in-tree user of SelectionDAG::getStrlen is the AIX path,
+ // where generic tail-calling to libcalls is not safe due to ABI
+ // constraints around r2 (TOC). We don¡¯t have a reliable way to validate a
+ // tail call here.
+ //
+ // If another target starts using this and does support tail calls to
+ // libcalls, re-enable `.setTailCall(...)` under a target guard and add a
+ // test.
+ CLI.setDebugLoc(dl).setChain(Chain).setLibCallee(
+ TLI->getLibcallCallingConv(RTLIB::STRLEN), CI->getType(),
+ getExternalSymbol(LibCallName, TLI->getProgramPointerTy(getDataLayout())),
+ std::move(Args));
return TLI->LowerCallTo(CLI);
}
diff --git a/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp b/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp
index e15b5b0bea2fc..93a4693c50168 100644
--- a/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp
@@ -33,6 +33,5 @@ std::pair<SDValue, SDValue>
PPCSelectionDAGInfo::EmitTargetCodeForStrlen(SelectionDAG &DAG, const SDLoc &DL,
SDValue Chain, SDValue Src,
const CallInst *CI) const {
- EVT PtrVT = Src.getValueType();
return DAG.getStrlen(Chain, DL, Src, CI);
}
>From 0c7f77469fa97558f8bf2ad9f2defabecea154ca Mon Sep 17 00:00:00 2001
From: zhijian <zhijian at ca.ibm.com>
Date: Fri, 22 Aug 2025 18:14:37 +0000
Subject: [PATCH 4/4] address comment
---
llvm/include/llvm/CodeGen/SelectionDAG.h | 7 +++----
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 13 ++-----------
2 files changed, 5 insertions(+), 15 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index 831e274b22ec4..9d43b2435b672 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -1256,10 +1256,9 @@ class SelectionDAG {
/// stack arguments from being clobbered.
LLVM_ABI SDValue getStackArgumentTokenFactor(SDValue Chain);
- LLVM_ABI std::pair<SDValue, SDValue> getMemcmp(SDValue Chain, const SDLoc &dl,
- SDValue Dst, SDValue Src,
- SDValue Size,
- const CallInst *CI);
+ std::pair<SDValue, SDValue> getMemcmp(SDValue Chain, const SDLoc &dl,
+ SDValue Dst, SDValue Src, SDValue Size,
+ const CallInst *CI);
LLVM_ABI std::pair<SDValue, SDValue>
getStrlen(SDValue Chain, const SDLoc &dl, SDValue Src, const CallInst *CI);
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index a2946736682a6..2b259ef3036d2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -9071,17 +9071,8 @@ std::pair<SDValue, SDValue> SelectionDAG::getStrlen(SDValue Chain,
TargetLowering::CallLoweringInfo CLI(*this);
- // TODO: Intentionally not marking this libcall as a tail call.
- //
- // Why:
- // - The only current in-tree user of SelectionDAG::getStrlen is the AIX path,
- // where generic tail-calling to libcalls is not safe due to ABI
- // constraints around r2 (TOC). We don¡¯t have a reliable way to validate a
- // tail call here.
- //
- // If another target starts using this and does support tail calls to
- // libcalls, re-enable `.setTailCall(...)` under a target guard and add a
- // test.
+ // 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())),
More information about the llvm-commits
mailing list