[llvm] [PowerPC] using milicode call for strcpy instead of lib call (PR #174782)
zhijian lin via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 7 07:01:42 PST 2026
https://github.com/diggerlin created https://github.com/llvm/llvm-project/pull/174782
AIX has "millicode" routines, which are functions loaded at boot time into fixed addresses in kernel memory. This allows them to be customized for the processor. The __strcpy routine is a millicode implementation; we use millicode for the strlen function instead of a library call to improve performance.
>From eb9036062212602a451eb8f4d7484abc889809ec Mon Sep 17 00:00:00 2001
From: zhijian <zhijian at ca.ibm.com>
Date: Thu, 13 Nov 2025 15:10:52 +0000
Subject: [PATCH] implement the milicode call strcpy
---
llvm/include/llvm/CodeGen/SelectionDAG.h | 6 +++++
.../llvm/CodeGen/SelectionDAGTargetInfo.h | 9 +++----
llvm/include/llvm/IR/RuntimeLibcalls.td | 2 ++
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 26 +++++++++++++++++++
.../SelectionDAG/SelectionDAGBuilder.cpp | 8 +++---
.../Target/PowerPC/PPCSelectionDAGInfo.cpp | 10 +++++++
llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.h | 8 ++++++
.../SystemZ/SystemZSelectionDAGInfo.cpp | 2 +-
.../Target/SystemZ/SystemZSelectionDAGInfo.h | 10 ++++---
9 files changed, 66 insertions(+), 15 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index 4c7c9942fb8f6..604319095e74f 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -1278,6 +1278,12 @@ class SelectionDAG {
SDValue Size,
const CallInst *CI);
+ /// Lower a strcpy operation into a target library call and return the
+ /// resulting chain and call result as SelectionDAG SDValues.
+ LLVM_ABI std::pair<SDValue, SDValue> getStrcpy(SDValue Chain, const SDLoc &dl,
+ SDValue Dst, SDValue Src,
+ const CallInst *CI);
+
/// Lower a strlen operation into a target library call and return the
/// resulting chain and call result as SelectionDAG SDValues.
LLVM_ABI std::pair<SDValue, SDValue>
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h b/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h
index fbfb240cae449..4761fac08c9d9 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h
@@ -140,11 +140,10 @@ class SelectionDAGTargetInfo {
/// of the destination string for strcpy, a pointer to the null terminator
/// for stpcpy) and the second is the chain. Both SDValues can be null
/// if a normal libcall should be used.
- virtual std::pair<SDValue, SDValue>
- EmitTargetCodeForStrcpy(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain,
- SDValue Dest, SDValue Src,
- MachinePointerInfo DestPtrInfo,
- MachinePointerInfo SrcPtrInfo, bool isStpcpy) const {
+ virtual std::pair<SDValue, SDValue> EmitTargetCodeForStrcpy(
+ SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dest,
+ SDValue Src, MachinePointerInfo DestPtrInfo,
+ MachinePointerInfo SrcPtrInfo, bool isStpcpy, 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 b9e68247de94d..e7d636841c4b9 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -3125,6 +3125,7 @@ defset list<RuntimeLibcallImpl> PPC64AIXCallList = {
def ___memmove64 : RuntimeLibcallImpl<MEMMOVE>;
def ___memset64 : RuntimeLibcallImpl<MEMSET>;
def ___bzero64 : RuntimeLibcallImpl<BZERO>;
+ def ___strcpy64 : RuntimeLibcallImpl<STRCPY>;
def ___strlen64 : RuntimeLibcallImpl<STRLEN>;
}
@@ -3133,6 +3134,7 @@ defset list<RuntimeLibcallImpl> PPC32AIXCallList = {
def ___memmove : RuntimeLibcallImpl<MEMMOVE>;
def ___memset : RuntimeLibcallImpl<MEMSET>;
def ___bzero : RuntimeLibcallImpl<BZERO>;
+ def ___strcpy : RuntimeLibcallImpl<STRCPY>;
def ___strlen : RuntimeLibcallImpl<STRLEN>;
}
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 15f86cb94f958..cc0baf4139ec1 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -9166,6 +9166,32 @@ SelectionDAG::getMemcmp(SDValue Chain, const SDLoc &dl, SDValue Mem0,
return TLI->LowerCallTo(CLI);
}
+std::pair<SDValue, SDValue> SelectionDAG::getStrcpy(SDValue Chain,
+ const SDLoc &dl,
+ SDValue Dst, SDValue Src,
+ const CallInst *CI) {
+ const char *LibCallName = TLI->getLibcallName(RTLIB::STRCPY);
+ if (!LibCallName)
+ return {};
+
+ PointerType *PT = PointerType::getUnqual(*getContext());
+ TargetLowering::ArgListTy Args = {{Dst, PT}, {Src, PT}};
+
+ TargetLowering::CallLoweringInfo CLI(*this);
+ bool IsTailCall =
+ isInTailCallPositionWrapper(CI, this, /*AllowReturnsFirstArg*/ true);
+
+ CLI.setDebugLoc(dl)
+ .setChain(Chain)
+ .setLibCallee(
+ TLI->getLibcallCallingConv(RTLIB::STRCPY), CI->getType(),
+ getExternalSymbol(LibCallName, TLI->getPointerTy(getDataLayout())),
+ std::move(Args))
+ .setTailCall(IsTailCall);
+
+ return TLI->LowerCallTo(CLI);
+}
+
std::pair<SDValue, SDValue> SelectionDAG::getStrlen(SDValue Chain,
const SDLoc &dl,
SDValue Src,
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index bff4799963fc2..7559784ed6ab1 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -9432,11 +9432,9 @@ bool SelectionDAGBuilder::visitStrCpyCall(const CallInst &I, bool isStpcpy) {
const Value *Arg0 = I.getArgOperand(0), *Arg1 = I.getArgOperand(1);
const SelectionDAGTargetInfo &TSI = DAG.getSelectionDAGInfo();
- std::pair<SDValue, SDValue> Res =
- TSI.EmitTargetCodeForStrcpy(DAG, getCurSDLoc(), getRoot(),
- getValue(Arg0), getValue(Arg1),
- MachinePointerInfo(Arg0),
- MachinePointerInfo(Arg1), isStpcpy);
+ std::pair<SDValue, SDValue> Res = TSI.EmitTargetCodeForStrcpy(
+ DAG, getCurSDLoc(), getRoot(), getValue(Arg0), getValue(Arg1),
+ MachinePointerInfo(Arg0), MachinePointerInfo(Arg1), isStpcpy, &I);
if (Res.first.getNode()) {
setValue(&I, Res.first);
DAG.setRoot(Res.second);
diff --git a/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp b/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp
index 80aa1122167df..cd58734c42c7a 100644
--- a/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.cpp
@@ -81,6 +81,16 @@ std::pair<SDValue, SDValue> PPCSelectionDAGInfo::EmitTargetCodeForMemcmp(
return DAG.getMemcmp(Chain, dl, Op1, Op2, Op3, CI);
}
+std::pair<SDValue, SDValue> PPCSelectionDAGInfo::EmitTargetCodeForStrcpy(
+ SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dest,
+ SDValue Src, MachinePointerInfo DestPtrInfo, MachinePointerInfo SrcPtrInfo,
+ bool isStpcpy, const CallInst *CI) const {
+ if (isStpcpy)
+ return SelectionDAGTargetInfo::EmitTargetCodeForStrcpy(
+ DAG, DL, Chain, Dest, Src, DestPtrInfo, SrcPtrInfo, isStpcpy, CI);
+ return DAG.getStrcpy(Chain, DL, Dest, Src, CI);
+}
+
std::pair<SDValue, SDValue>
PPCSelectionDAGInfo::EmitTargetCodeForStrlen(SelectionDAG &DAG, const SDLoc &DL,
SDValue Chain, SDValue Src,
diff --git a/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.h b/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.h
index ffe8982ce1af4..0324a24341a45 100644
--- a/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.h
+++ b/llvm/lib/Target/PowerPC/PPCSelectionDAGInfo.h
@@ -76,6 +76,14 @@ class PPCSelectionDAGInfo : public SelectionDAGGenTargetInfo {
EmitTargetCodeForMemcmp(SelectionDAG &DAG, const SDLoc &dl, SDValue Chain,
SDValue Op1, SDValue Op2, SDValue Op3,
const CallInst *CI) const override;
+
+ std::pair<SDValue, SDValue>
+ EmitTargetCodeForStrcpy(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain,
+ SDValue Dest, SDValue Src,
+ MachinePointerInfo DestPtrInfo,
+ MachinePointerInfo SrcPtrInfo, bool isStpcpy,
+ const CallInst *CI) const override;
+
std::pair<SDValue, SDValue>
EmitTargetCodeForStrlen(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain,
SDValue Src, const CallInst *CI) const override;
diff --git a/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp b/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp
index 88feba8adce0e..afffeb52da879 100644
--- a/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.cpp
@@ -229,7 +229,7 @@ std::pair<SDValue, SDValue> SystemZSelectionDAGInfo::EmitTargetCodeForMemchr(
std::pair<SDValue, SDValue> SystemZSelectionDAGInfo::EmitTargetCodeForStrcpy(
SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dest,
SDValue Src, MachinePointerInfo DestPtrInfo, MachinePointerInfo SrcPtrInfo,
- bool isStpcpy) const {
+ bool isStpcpy, const CallInst *CI) const {
SDVTList VTs = DAG.getVTList(Dest.getValueType(), MVT::Other);
SDValue EndDest = DAG.getNode(SystemZISD::STPCPY, DL, VTs, Chain, Dest, Src,
DAG.getConstant(0, DL, MVT::i32));
diff --git a/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.h b/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.h
index d25fddab65161..6da36c9bc4225 100644
--- a/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.h
+++ b/llvm/lib/Target/SystemZ/SystemZSelectionDAGInfo.h
@@ -67,10 +67,12 @@ class SystemZSelectionDAGInfo : public SelectionDAGGenTargetInfo {
SDValue Src, SDValue Char, SDValue Length,
MachinePointerInfo SrcPtrInfo) const override;
- std::pair<SDValue, SDValue> EmitTargetCodeForStrcpy(
- SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dest,
- SDValue Src, MachinePointerInfo DestPtrInfo,
- MachinePointerInfo SrcPtrInfo, bool isStpcpy) const override;
+ std::pair<SDValue, SDValue>
+ EmitTargetCodeForStrcpy(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain,
+ SDValue Dest, SDValue Src,
+ MachinePointerInfo DestPtrInfo,
+ MachinePointerInfo SrcPtrInfo, bool isStpcpy,
+ const CallInst *CI) const override;
std::pair<SDValue, SDValue>
EmitTargetCodeForStrcmp(SelectionDAG &DAG, const SDLoc &DL, SDValue Chain,
More information about the llvm-commits
mailing list