Skip to content

[PowerPC][AIX] Using milicode for memcmp instead of libcall #147093

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

diggerlin
Copy link
Contributor

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 __memcmp routine is a millicode implementation; we use millicode for the memcmp function instead of a library call to improve performance.

@llvmbot llvmbot added backend:PowerPC llvm:SelectionDAG SelectionDAGISel as well labels Jul 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 4, 2025

@llvm/pr-subscribers-llvm-ir
@llvm/pr-subscribers-backend-systemz
@llvm/pr-subscribers-llvm-selectiondag

@llvm/pr-subscribers-backend-powerpc

Author: zhijian lin (diggerlin)

Changes

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 __memcmp routine is a millicode implementation; we use millicode for the memcmp function instead of a library call to improve performance.


Full diff: https://github.com/llvm/llvm-project/pull/147093.diff

3 Files Affected:

  • (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (+8-1)
  • (modified) llvm/test/CodeGen/PowerPC/memintr32.ll (+1-1)
  • (modified) llvm/test/CodeGen/PowerPC/memintr64.ll (+1-1)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index ecd1ff87e7fbc..5bc71bdbccf43 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -9065,8 +9065,15 @@ bool SelectionDAGBuilder::visitMemCmpBCmpCall(const CallInst &I) {
 
   // memcmp(S1,S2,2) != 0 -> (*(short*)LHS != *(short*)RHS)  != 0
   // memcmp(S1,S2,4) != 0 -> (*(int*)LHS != *(int*)RHS)  != 0
-  if (!CSize || !isOnlyUsedInZeroEqualityComparison(&I))
+  if (!CSize || !isOnlyUsedInZeroEqualityComparison(&I)) {
+    const Triple& TheTriple = TM.getTargetTriple();
+    if(TheTriple.isOSAIX()) {
+      if (Function *F = I.getCalledFunction()) {
+	F->setName(TheTriple.isArch32Bit() ? "___memcmp" : "___memcmp64");
+      }
+    }
     return false;
+  }
 
   // If the target has a fast compare for the given size, it will return a
   // preferred load type for that size. Require that the load VT is legal and
diff --git a/llvm/test/CodeGen/PowerPC/memintr32.ll b/llvm/test/CodeGen/PowerPC/memintr32.ll
index c07a5af17e48a..4f0a9960a546d 100644
--- a/llvm/test/CodeGen/PowerPC/memintr32.ll
+++ b/llvm/test/CodeGen/PowerPC/memintr32.ll
@@ -11,7 +11,7 @@ define i32 @memcmp_test(ptr nocapture noundef readonly %ptr1, ptr nocapture noun
 ; CHECK-AIX-32-P9-NEXT:    mflr r0
 ; CHECK-AIX-32-P9-NEXT:    stwu r1, -64(r1)
 ; CHECK-AIX-32-P9-NEXT:    stw r0, 72(r1)
-; CHECK-AIX-32-P9-NEXT:    bl .memcmp[PR]
+; CHECK-AIX-32-P9-NEXT:    bl .___memcmp[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/memintr64.ll b/llvm/test/CodeGen/PowerPC/memintr64.ll
index b3a6650b8f6e6..0b0e556e89b51 100644
--- a/llvm/test/CodeGen/PowerPC/memintr64.ll
+++ b/llvm/test/CodeGen/PowerPC/memintr64.ll
@@ -39,7 +39,7 @@ define noundef i32 @_Z11memcmp_testPKvS0_m(ptr noundef readonly captures(none) %
 ; CHECK-AIX-64-P9-NEXT:    mflr r0
 ; CHECK-AIX-64-P9-NEXT:    stdu r1, -112(r1)
 ; CHECK-AIX-64-P9-NEXT:    std r0, 128(r1)
-; CHECK-AIX-64-P9-NEXT:    bl .memcmp[PR]
+; CHECK-AIX-64-P9-NEXT:    bl .___memcmp64[PR]
 ; CHECK-AIX-64-P9-NEXT:    nop
 ; CHECK-AIX-64-P9-NEXT:    addi r1, r1, 112
 ; CHECK-AIX-64-P9-NEXT:    ld r0, 16(r1)

Copy link

github-actions bot commented Jul 4, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@diggerlin diggerlin removed the request for review from stefanp-synopsys July 4, 2025 18:10
Copy link
Contributor

@lei137 lei137 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please apply clang-format to your changes.

Copy link
Contributor

@arsenm arsenm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler should not directly emit string calls. This needs an entry in RuntimeLibcalls.td to emit the call. Further, this should not be based on a triple call in the DAG builder

const Triple& TheTriple = TM.getTargetTriple();
if(TheTriple.isOSAIX()) {
if (Function *F = I.getCalledFunction()) {
F->setName(TheTriple.isArch32Bit() ? "___memcmp" : "___memcmp64");
Copy link
Contributor

@arsenm arsenm Jul 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also mutating the IR, you cannot do that in codegen. It's also mutating the function itself, and not the call target

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also mutating the IR, you cannot do that in codegen. It's also mutating the function itself, and not the call target

do you means, we can not change the IR ?
in AIX, the function name will be used to generate an external symbol. and the AIX OS linker and loader will use the external symbol to find the correct function address in the memory , if we change the function name memcmp to function name to "___memcmp" (or ___memcmp64 for 64-bit AIX OS), it will change the call target.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You cannot change the IR, and you definitely cannot change a function name in a function pass. You either need to have this done in a separate IR pass (and change the call target to an explicit declaration of the new name), or directly change the call target that is emitted here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case you should be querying if there is an implementation of RTLIB::MEMCMP, and configuring the target to use RTLIB::___memcmp for RTLIB::MEMCMP

@diggerlin
Copy link
Contributor Author

diggerlin commented Jul 7, 2025

The compiler should not directly emit string calls. This needs an entry in RuntimeLibcalls.td to emit the call.

The memcmp is in the RuntimeLibcalls.td, the ___memcmp has the same signature as memcmp. They are just have different function name, and memcmp is a lib call , but the ___memcmp is "millicode" routines, which are functions loaded at boot time into fixed addresses in kernel memory. In the link stage, the AIX linker will replace the __memcmp sybol with memory address of the __memcmp

Further, this should not be based on a triple call in the DAG builder

I will try not to use the triple call in the DAG builder

@diggerlin diggerlin requested a review from arsenm July 7, 2025 17:28
@arsenm
Copy link
Contributor

arsenm commented Jul 8, 2025

The memcmp is in the RuntimeLibcalls.td, the ___memcmp has the same signature as memcmp. They are just have different function name, and memcmp is a lib call ,

Which is why they have separate entries in RuntimeLibcalls for the implementations. Every call target emitted by the compiler should be tracked in RuntimeLibcalls, and selectable through a generated enum value. No code should continue to emit functions directly by string name

@diggerlin diggerlin force-pushed the digger/milicode-memcpy branch from 303de25 to 97837a2 Compare July 9, 2025 19:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants