[llvm] [PowerPC] simplify the asm of scmp builtin (PR #200024)

zhijian lin via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 1 08:03:25 PDT 2026


https://github.com/diggerlin updated https://github.com/llvm/llvm-project/pull/200024

>From da1095f9d0aaf007479597b9efa4d8002b2a44a9 Mon Sep 17 00:00:00 2001
From: zhijian <zhijian at ca.ibm.com>
Date: Thu, 14 May 2026 15:36:33 +0000
Subject: [PATCH 1/4] first implement of db2 issue124

---
 llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 132 ++++++++++++++++++++
 llvm/lib/Target/PowerPC/PPCISelLowering.cpp |  95 ++++++++++++++
 llvm/lib/Target/PowerPC/PPCISelLowering.h   |   1 +
 3 files changed, 228 insertions(+)

diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index 016c547821f7a..7cfe6846a48fe 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -217,6 +217,7 @@ namespace {
     bool tryBitfieldInsert(SDNode *N);
     bool tryBitPermutation(SDNode *N);
     bool tryIntCompareInGPR(SDNode *N);
+    bool trySelectThreeWayCompare(SDNode *N);
 
     // tryTLSXFormLoad - Convert an ISD::LOAD fed by a PPCISD::ADD_TLS into
     // an X-Form load instruction with the offset being a relocation coming from
@@ -3765,6 +3766,7 @@ IntegerCompareEliminator::get64BitZExtCompare(SDValue LHS, SDValue RHS,
       return SDValue(CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64, LHS,
                                             S->getI64Imm(1, dl),
                                             S->getI64Imm(63, dl)), 0);
+
     SDValue SRADINode =
       SDValue(CurDAG->getMachineNode(PPC::SRADI, dl, MVT::i64,
                                      LHS, S->getI64Imm(63, dl)), 0);
@@ -4051,6 +4053,131 @@ SDValue IntegerCompareEliminator::getSETCCInGPR(SDValue Compare,
 
 } // end anonymous namespace
 
+bool PPCDAGToDAGISel::trySelectThreeWayCompare(SDNode *N) {
+  // Match pattern: select (setcc a, b, setlt), -1, (zext (setcc a, b, setgt))
+  // This is the three-way comparison pattern (like C++20 operator<=>)
+  // Generate optimal code using single comparison with MFOCRF
+
+  if (N->getOpcode() != ISD::SELECT)
+    return false;
+
+  // Only optimize for targets with MFOCRF support
+  if (!Subtarget->hasMFOCRF())
+    return false;
+
+  SDValue Cond = N->getOperand(0);
+  SDValue TrueVal = N->getOperand(1);
+  SDValue FalseVal = N->getOperand(2);
+
+  // Check if condition is SETCC with SETLT
+  if (Cond.getOpcode() != ISD::SETCC)
+    return false;
+
+  ISD::CondCode CC = cast<CondCodeSDNode>(Cond.getOperand(2))->get();
+  if (CC != ISD::SETLT)
+    return false;
+
+  SDValue LHS = Cond.getOperand(0);
+  SDValue RHS = Cond.getOperand(1);
+
+  // Check operand types - support both i32 and i64
+  EVT CmpVT = LHS.getValueType();
+  if (CmpVT != MVT::i32 && CmpVT != MVT::i64)
+    return false;
+
+  if (RHS.getValueType() != CmpVT)
+    return false;
+
+  // Check if TrueVal is -1
+  ConstantSDNode *TrueConst = dyn_cast<ConstantSDNode>(TrueVal);
+  if (!TrueConst || !TrueConst->isAllOnes())
+    return false;
+
+  // Check if FalseVal is ZERO_EXTEND
+  if (FalseVal.getOpcode() != ISD::ZERO_EXTEND)
+    return false;
+
+  SDValue InnerSetcc = FalseVal.getOperand(0);
+  if (InnerSetcc.getOpcode() != ISD::SETCC)
+    return false;
+
+  // Check if inner SETCC is SETGT with same operands
+  ISD::CondCode InnerCC = cast<CondCodeSDNode>(InnerSetcc.getOperand(2))->get();
+  if (InnerCC != ISD::SETGT)
+    return false;
+
+  SDValue InnerLHS = InnerSetcc.getOperand(0);
+  SDValue InnerRHS = InnerSetcc.getOperand(1);
+
+  if (LHS != InnerLHS || RHS != InnerRHS)
+    return false;
+
+  // Pattern matched! Generate optimal code:
+  // cmpd/cmpw cr7, LHS, RHS
+  // mfocrf r, 1
+  // rldicl/rlwinm LT, r, 62/2, 63/31  (extract LT bit)
+  // rldicl/rlwinm GT, r, 61/1, 63/31  (extract GT bit)
+  // subf result, GT, LT   (LT - GT = -1/0/1)
+
+  SDLoc dl(N);
+  bool Is64BitCmp = (CmpVT == MVT::i64);
+  EVT ResVT = N->getValueType(0);
+  bool Is64BitRes = (ResVT == MVT::i64);
+
+  // Generate comparison to CR7
+  unsigned CmpOpc = Is64BitCmp ? PPC::CMPD : PPC::CMPW;
+  SDValue Cmp =
+      SDValue(CurDAG->getMachineNode(CmpOpc, dl, MVT::i32, LHS, RHS), 0);
+
+  unsigned MFOCRFOpc = Is64BitRes ? PPC::MFOCRF8 : PPC::MFOCRF;
+  EVT MFVT = Is64BitRes ? MVT::i64 : MVT::i32;
+  SDValue MFOCRF = SDValue(CurDAG->getMachineNode(MFOCRFOpc, dl, MFVT, Cmp), 0);
+
+  // Extract LT and GT bits (match result type)
+  SDValue LTBit, GTBit;
+
+  if (Is64BitRes) {
+    // Extract LT bit (bit 0 of CR -> rotate left 62, clear left 63)
+    LTBit = SDValue(
+        CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64, MFOCRF,
+                               CurDAG->getTargetConstant(62, dl, MVT::i64),
+                               CurDAG->getTargetConstant(63, dl, MVT::i64)),
+        0);
+
+    // Extract GT bit (bit 1 of CR -> rotate left 61, clear left 63)
+    GTBit = SDValue(
+        CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64, MFOCRF,
+                               CurDAG->getTargetConstant(61, dl, MVT::i64),
+                               CurDAG->getTargetConstant(63, dl, MVT::i64)),
+        0);
+  } else {
+    // 32-bit: Extract LT bit (bit 0 of CR -> rotate left 2, mask bit 31)
+    SDValue LTOps[] = {MFOCRF, CurDAG->getTargetConstant(2, dl, MVT::i32),
+                       CurDAG->getTargetConstant(31, dl, MVT::i32),
+                       CurDAG->getTargetConstant(31, dl, MVT::i32)};
+    LTBit =
+        SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, LTOps), 0);
+
+    // Extract GT bit (bit 1 of CR7 -> rotate left 1, mask bit 31)
+    SDValue GTOps[] = {MFOCRF, CurDAG->getTargetConstant(1, dl, MVT::i32),
+                       CurDAG->getTargetConstant(31, dl, MVT::i32),
+                       CurDAG->getTargetConstant(31, dl, MVT::i32)};
+    GTBit =
+        SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, GTOps), 0);
+  }
+
+  // Compute result: GT - LT (match result type)
+  // If LT: 0 - 1 = -1 ✓
+  // If GT: 1 - 0 = 1 ✓
+  // If EQ: 0 - 0 = 0 ✓
+  unsigned SubOpc = Is64BitRes ? PPC::SUBF8 : PPC::SUBF;
+  SDValue Result =
+      SDValue(CurDAG->getMachineNode(SubOpc, dl, ResVT, LTBit, GTBit), 0);
+
+  ReplaceNode(N, Result.getNode());
+  return true;
+}
+
 bool PPCDAGToDAGISel::tryIntCompareInGPR(SDNode *N) {
   if (N->getValueType(0) != MVT::i32 &&
       N->getValueType(0) != MVT::i64)
@@ -5273,6 +5400,11 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
   if (tryIntCompareInGPR(N))
     return;
 
+  // Try to match the three-way comparison pattern:
+  // select (setcc a, b, setlt), -1, (zext (setcc a, b, setgt))
+  if (trySelectThreeWayCompare(N))
+    return;
+
   switch (N->getOpcode()) {
   default: break;
 
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 407093fd2b849..f13cb517b8572 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -15916,6 +15916,99 @@ SDValue PPCTargetLowering::combineSignExtendSetCC(SDNode *N,
   return Sube;
 }
 
+// Optimize: sign_extend(select(cond, op1, op2))
+// where operands are constants, zero_extend, or sign_extend
+// For 64-bit targets, we can eliminate the outer sign_extend by hoisting
+// operations to i64, reducing one instruction.
+SDValue PPCTargetLowering::combineSignExtendSelect(SDNode *N,
+                                                   DAGCombinerInfo &DCI) const {
+  // Only optimize on 64-bit targets where i64 is a legal type
+  if (!Subtarget.isPPC64())
+    return SDValue();
+
+  assert(N->getOpcode() == ISD::SIGN_EXTEND && "Expected SIGN_EXTEND node");
+
+  EVT VT = N->getValueType(0);
+  if (VT != MVT::i64)
+    return SDValue();
+
+  SDValue N0 = N->getOperand(0);
+
+  // Check if operand is a SELECT node with i32 result type
+  if (N0.getOpcode() != ISD::SELECT || N0.getValueType() != MVT::i32)
+    return SDValue();
+
+  // Only optimize if the SELECT has a single use to avoid duplicating work
+  if (!N0.hasOneUse())
+    return SDValue();
+
+  SDValue Cond = N0.getOperand(0);
+  SDValue TrueVal = N0.getOperand(1);
+  SDValue FalseVal = N0.getOperand(2);
+
+  // Check if operands are constants or extend operations
+  // This optimization is beneficial when we can avoid intermediate i32
+  // operations
+
+  auto IsOptimizableOperand = [](SDValue V) -> bool {
+    if (isa<ConstantSDNode>(V))
+      return true;
+    if (V.getOpcode() == ISD::ZERO_EXTEND || V.getOpcode() == ISD::SIGN_EXTEND)
+      return true;
+    return false;
+  };
+
+  bool TrueIsOptimizable = IsOptimizableOperand(TrueVal);
+  bool FalseIsOptimizable = IsOptimizableOperand(FalseVal);
+
+  // Only optimize if at least one operand matches our pattern
+  if (!TrueIsOptimizable && !FalseIsOptimizable)
+    return SDValue();
+
+  // Check hasOneUse for extend nodes to avoid duplication
+  if ((TrueVal.getOpcode() == ISD::ZERO_EXTEND ||
+       TrueVal.getOpcode() == ISD::SIGN_EXTEND) &&
+      !TrueVal.hasOneUse())
+    return SDValue();
+  if ((FalseVal.getOpcode() == ISD::ZERO_EXTEND ||
+       FalseVal.getOpcode() == ISD::SIGN_EXTEND) &&
+      !FalseVal.hasOneUse())
+    return SDValue();
+
+  // Pattern matched: sext(select(cond, op1, op2))
+  // Transform to: select(cond, sext(op1), sext(op2))
+  // This eliminates the outer sign_extend operation.
+
+  SelectionDAG &DAG = DCI.DAG;
+  SDLoc dl(N);
+
+  // Helper to extend operand to i64
+  auto ExtendOperand = [&](SDValue Op) -> SDValue {
+    if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) {
+      // Sign-extend constant
+      return DAG.getConstant(C->getSExtValue(), dl, MVT::i64);
+    } else if (Op.getOpcode() == ISD::ZERO_EXTEND) {
+      // Extend zero_extend: zext(x) -> zext_i64(x)
+      return DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, Op.getOperand(0));
+    } else if (Op.getOpcode() == ISD::SIGN_EXTEND) {
+      // Extend sign_extend: sext(x) -> sext_i64(x)
+      return DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::i64, Op.getOperand(0));
+    } else {
+      // Sign-extend other values
+      return DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::i64, Op);
+    }
+  };
+
+  SDValue NewTrueVal = ExtendOperand(TrueVal);
+  SDValue NewFalseVal = ExtendOperand(FalseVal);
+
+  // Create the new i64 select
+  SDValue NewSelect =
+      DAG.getNode(ISD::SELECT, dl, MVT::i64, Cond, NewTrueVal, NewFalseVal);
+
+  return NewSelect;
+}
+
 SDValue PPCTargetLowering::combineSetCC(SDNode *N,
                                         DAGCombinerInfo &DCI) const {
   assert(N->getOpcode() == ISD::SETCC &&
@@ -17589,6 +17682,8 @@ SDValue PPCTargetLowering::PerformDAGCombine(SDNode *N,
   case ISD::SIGN_EXTEND:
     if (SDValue SECC = combineSignExtendSetCC(N, DCI))
       return SECC;
+    if (SDValue SEXT = combineSignExtendSelect(N, DCI))
+      return SEXT;
     [[fallthrough]];
   case ISD::ZERO_EXTEND:
     if (SDValue RetV = combineZextSetccWithZero(N, DCI.DAG))
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h
index 1778da5aba2fd..29830d9067a45 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.h
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h
@@ -871,6 +871,7 @@ namespace llvm {
     SDValue combineADD(SDNode *N, DAGCombinerInfo &DCI) const;
     SDValue combineFMALike(SDNode *N, DAGCombinerInfo &DCI) const;
     SDValue combineTRUNCATE(SDNode *N, DAGCombinerInfo &DCI) const;
+    SDValue combineSignExtendSelect(SDNode *N, DAGCombinerInfo &DCI) const;
     SDValue combineSignExtendSetCC(SDNode *N, DAGCombinerInfo &DCI) const;
     SDValue combineSetCC(SDNode *N, DAGCombinerInfo &DCI) const;
     SDValue combineVectorShuffle(ShuffleVectorSDNode *SVN,

>From d279f06226743876f4210c8008063d61f95518f6 Mon Sep 17 00:00:00 2001
From: zhijian <zhijian at ca.ibm.com>
Date: Wed, 27 May 2026 18:24:07 +0000
Subject: [PATCH 2/4] changed test case based on the new functionality

---
 llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp |  5 +-
 llvm/test/CodeGen/PowerPC/ppc64-P9-setb.ll  |  2 -
 llvm/test/CodeGen/PowerPC/scmp.ll           | 65 +++++++++------------
 3 files changed, 28 insertions(+), 44 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index 7cfe6846a48fe..ade98dc6b7dfc 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -4113,8 +4113,8 @@ bool PPCDAGToDAGISel::trySelectThreeWayCompare(SDNode *N) {
     return false;
 
   // Pattern matched! Generate optimal code:
-  // cmpd/cmpw cr7, LHS, RHS
-  // mfocrf r, 1
+  // cmpd/cmpw  LHS, RHS
+  // mfocrf RT, FXM
   // rldicl/rlwinm LT, r, 62/2, 63/31  (extract LT bit)
   // rldicl/rlwinm GT, r, 61/1, 63/31  (extract GT bit)
   // subf result, GT, LT   (LT - GT = -1/0/1)
@@ -4124,7 +4124,6 @@ bool PPCDAGToDAGISel::trySelectThreeWayCompare(SDNode *N) {
   EVT ResVT = N->getValueType(0);
   bool Is64BitRes = (ResVT == MVT::i64);
 
-  // Generate comparison to CR7
   unsigned CmpOpc = Is64BitCmp ? PPC::CMPD : PPC::CMPW;
   SDValue Cmp =
       SDValue(CurDAG->getMachineNode(CmpOpc, dl, MVT::i32, LHS, RHS), 0);
diff --git a/llvm/test/CodeGen/PowerPC/ppc64-P9-setb.ll b/llvm/test/CodeGen/PowerPC/ppc64-P9-setb.ll
index a2a5c6c5eafb7..990821caec1d5 100644
--- a/llvm/test/CodeGen/PowerPC/ppc64-P9-setb.ll
+++ b/llvm/test/CodeGen/PowerPC/ppc64-P9-setb.ll
@@ -673,7 +673,6 @@ define i64 @setb27(i64 %a, i64 %b) {
 ; CHECK-PWR8-NEXT:    addic r6, r5, -1
 ; CHECK-PWR8-NEXT:    subfe r5, r6, r5
 ; CHECK-PWR8-NEXT:    isellt r3, r3, r5
-; CHECK-PWR8-NEXT:    extsw r3, r3
 ; CHECK-PWR8-NEXT:    blr
   %t1 = icmp slt i64 %a, %b
   %t2 = icmp ne i64 %b, %a
@@ -699,7 +698,6 @@ define i64 @setb28(i64 %a, i64 %b) {
 ; CHECK-PWR8-NEXT:    addic r6, r5, -1
 ; CHECK-PWR8-NEXT:    subfe r5, r6, r5
 ; CHECK-PWR8-NEXT:    iselgt r3, r3, r5
-; CHECK-PWR8-NEXT:    extsw r3, r3
 ; CHECK-PWR8-NEXT:    blr
   %t1 = icmp sgt i64 %b, %a
   %t2 = icmp ne i64 %b, %a
diff --git a/llvm/test/CodeGen/PowerPC/scmp.ll b/llvm/test/CodeGen/PowerPC/scmp.ll
index 107137c0bea7c..14cf81536546f 100644
--- a/llvm/test/CodeGen/PowerPC/scmp.ll
+++ b/llvm/test/CodeGen/PowerPC/scmp.ll
@@ -5,10 +5,10 @@ define i8 @scmp_8_8(i8 signext %x, i8 signext %y) nounwind {
 ; CHECK-LABEL: scmp_8_8:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    cmpw 3, 4
-; CHECK-NEXT:    sub 5, 4, 3
-; CHECK-NEXT:    li 3, -1
-; CHECK-NEXT:    rldicl 5, 5, 1, 63
-; CHECK-NEXT:    isellt 3, 3, 5
+; CHECK-NEXT:    mfocrf 3, 128
+; CHECK-NEXT:    srwi 4, 3, 31
+; CHECK-NEXT:    rlwinm 3, 3, 2, 31, 31
+; CHECK-NEXT:    sub 3, 4, 3
 ; CHECK-NEXT:    blr
   %1 = call i8 @llvm.scmp(i8 %x, i8 %y)
   ret i8 %1
@@ -18,10 +18,10 @@ define i8 @scmp_8_16(i16 signext %x, i16 signext %y) nounwind {
 ; CHECK-LABEL: scmp_8_16:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    cmpw 3, 4
-; CHECK-NEXT:    sub 5, 4, 3
-; CHECK-NEXT:    li 3, -1
-; CHECK-NEXT:    rldicl 5, 5, 1, 63
-; CHECK-NEXT:    isellt 3, 3, 5
+; CHECK-NEXT:    mfocrf 3, 128
+; CHECK-NEXT:    srwi 4, 3, 31
+; CHECK-NEXT:    rlwinm 3, 3, 2, 31, 31
+; CHECK-NEXT:    sub 3, 4, 3
 ; CHECK-NEXT:    blr
   %1 = call i8 @llvm.scmp(i16 %x, i16 %y)
   ret i8 %1
@@ -30,13 +30,11 @@ define i8 @scmp_8_16(i16 signext %x, i16 signext %y) nounwind {
 define i8 @scmp_8_32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: scmp_8_32:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    extsw 4, 4
-; CHECK-NEXT:    extsw 3, 3
 ; CHECK-NEXT:    cmpw 3, 4
+; CHECK-NEXT:    mfocrf 3, 128
+; CHECK-NEXT:    srwi 4, 3, 31
+; CHECK-NEXT:    rlwinm 3, 3, 2, 31, 31
 ; CHECK-NEXT:    sub 3, 4, 3
-; CHECK-NEXT:    li 4, -1
-; CHECK-NEXT:    rldicl 3, 3, 1, 63
-; CHECK-NEXT:    isellt 3, 4, 3
 ; CHECK-NEXT:    blr
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
   ret i8 %1
@@ -45,14 +43,11 @@ define i8 @scmp_8_32(i32 %x, i32 %y) nounwind {
 define i8 @scmp_8_64(i64 %x, i64 %y) nounwind {
 ; CHECK-LABEL: scmp_8_64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    sradi 5, 4, 63
-; CHECK-NEXT:    rldicl 6, 3, 1, 63
-; CHECK-NEXT:    subc 7, 4, 3
-; CHECK-NEXT:    adde 5, 6, 5
 ; CHECK-NEXT:    cmpd 3, 4
-; CHECK-NEXT:    li 3, -1
-; CHECK-NEXT:    xori 5, 5, 1
-; CHECK-NEXT:    isellt 3, 3, 5
+; CHECK-NEXT:    mfocrf 3, 128
+; CHECK-NEXT:    srwi 4, 3, 31
+; CHECK-NEXT:    rlwinm 3, 3, 2, 31, 31
+; CHECK-NEXT:    sub 3, 4, 3
 ; CHECK-NEXT:    blr
   %1 = call i8 @llvm.scmp(i64 %x, i64 %y)
   ret i8 %1
@@ -82,13 +77,11 @@ define i8 @scmp_8_128(i128 %x, i128 %y) nounwind {
 define i32 @scmp_32_32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: scmp_32_32:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    extsw 4, 4
-; CHECK-NEXT:    extsw 3, 3
 ; CHECK-NEXT:    cmpw 3, 4
+; CHECK-NEXT:    mfocrf 3, 128
+; CHECK-NEXT:    srwi 4, 3, 31
+; CHECK-NEXT:    rlwinm 3, 3, 2, 31, 31
 ; CHECK-NEXT:    sub 3, 4, 3
-; CHECK-NEXT:    li 4, -1
-; CHECK-NEXT:    rldicl 3, 3, 1, 63
-; CHECK-NEXT:    isellt 3, 4, 3
 ; CHECK-NEXT:    blr
   %1 = call i32 @llvm.scmp(i32 %x, i32 %y)
   ret i32 %1
@@ -97,14 +90,11 @@ define i32 @scmp_32_32(i32 %x, i32 %y) nounwind {
 define i32 @scmp_32_64(i64 %x, i64 %y) nounwind {
 ; CHECK-LABEL: scmp_32_64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    sradi 5, 4, 63
-; CHECK-NEXT:    rldicl 6, 3, 1, 63
-; CHECK-NEXT:    subc 7, 4, 3
-; CHECK-NEXT:    adde 5, 6, 5
 ; CHECK-NEXT:    cmpd 3, 4
-; CHECK-NEXT:    li 3, -1
-; CHECK-NEXT:    xori 5, 5, 1
-; CHECK-NEXT:    isellt 3, 3, 5
+; CHECK-NEXT:    mfocrf 3, 128
+; CHECK-NEXT:    srwi 4, 3, 31
+; CHECK-NEXT:    rlwinm 3, 3, 2, 31, 31
+; CHECK-NEXT:    sub 3, 4, 3
 ; CHECK-NEXT:    blr
   %1 = call i32 @llvm.scmp(i64 %x, i64 %y)
   ret i32 %1
@@ -113,14 +103,11 @@ define i32 @scmp_32_64(i64 %x, i64 %y) nounwind {
 define i64 @scmp_64_64(i64 %x, i64 %y) nounwind {
 ; CHECK-LABEL: scmp_64_64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    sradi 5, 4, 63
-; CHECK-NEXT:    rldicl 6, 3, 1, 63
-; CHECK-NEXT:    subc 7, 4, 3
-; CHECK-NEXT:    adde 5, 6, 5
 ; CHECK-NEXT:    cmpd 3, 4
-; CHECK-NEXT:    li 3, -1
-; CHECK-NEXT:    xori 5, 5, 1
-; CHECK-NEXT:    isellt 3, 3, 5
+; CHECK-NEXT:    mfocrf 3, 128
+; CHECK-NEXT:    rldicl 4, 3, 61, 63
+; CHECK-NEXT:    rldicl 3, 3, 62, 63
+; CHECK-NEXT:    sub 3, 4, 3
 ; CHECK-NEXT:    blr
   %1 = call i64 @llvm.scmp(i64 %x, i64 %y)
   ret i64 %1

>From 056d9ceb93d611a4b7087ede3429eeffd80fe28e Mon Sep 17 00:00:00 2001
From: zhijian <zhijian at ca.ibm.com>
Date: Mon, 1 Jun 2026 15:02:29 +0000
Subject: [PATCH 3/4] force to cr7 field

---
 llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 33 ++++++++-----
 llvm/test/CodeGen/PowerPC/scmp.ll           | 52 ++++++++++-----------
 2 files changed, 47 insertions(+), 38 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index ade98dc6b7dfc..a5bdd640f1fae 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -4128,37 +4128,46 @@ bool PPCDAGToDAGISel::trySelectThreeWayCompare(SDNode *N) {
   SDValue Cmp =
       SDValue(CurDAG->getMachineNode(CmpOpc, dl, MVT::i32, LHS, RHS), 0);
 
+  // Force the comparison result into CR7 so we know exact bit positions
+  SDValue CR7Reg = CurDAG->getRegister(PPC::CR7, MVT::i32);
+  SDValue InGlue;  // Null incoming flag value
+  SDValue CopyToReg = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, CR7Reg, Cmp, InGlue);
+  SDValue Glue = CopyToReg.getValue(1);
+
+  // Now use MFOCRF with CR7
   unsigned MFOCRFOpc = Is64BitRes ? PPC::MFOCRF8 : PPC::MFOCRF;
   EVT MFVT = Is64BitRes ? MVT::i64 : MVT::i32;
-  SDValue MFOCRF = SDValue(CurDAG->getMachineNode(MFOCRFOpc, dl, MFVT, Cmp), 0);
+  SDValue MFOCRF = SDValue(CurDAG->getMachineNode(MFOCRFOpc, dl, MFVT, CR7Reg, Glue), 0);
 
-  // Extract LT and GT bits (match result type)
+  // Extract LT and GT bits from CR7
   SDValue LTBit, GTBit;
 
   if (Is64BitRes) {
-    // Extract LT bit (bit 0 of CR -> rotate left 62, clear left 63)
+    // For 64-bit: CR7 extraction using rldicl
+    // rldicl r, r, 62, 63 - extract LT
     LTBit = SDValue(
         CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64, MFOCRF,
-                               CurDAG->getTargetConstant(62, dl, MVT::i64),
-                               CurDAG->getTargetConstant(63, dl, MVT::i64)),
+                               CurDAG->getTargetConstant(62, dl, MVT::i32),
+                               CurDAG->getTargetConstant(63, dl, MVT::i32)),
         0);
 
-    // Extract GT bit (bit 1 of CR -> rotate left 61, clear left 63)
+    // rldicl r, r, 61, 63 - extract GT
     GTBit = SDValue(
         CurDAG->getMachineNode(PPC::RLDICL, dl, MVT::i64, MFOCRF,
-                               CurDAG->getTargetConstant(61, dl, MVT::i64),
-                               CurDAG->getTargetConstant(63, dl, MVT::i64)),
+                               CurDAG->getTargetConstant(61, dl, MVT::i32),
+                               CurDAG->getTargetConstant(63, dl, MVT::i32)),
         0);
   } else {
-    // 32-bit: Extract LT bit (bit 0 of CR -> rotate left 2, mask bit 31)
-    SDValue LTOps[] = {MFOCRF, CurDAG->getTargetConstant(2, dl, MVT::i32),
+    // 32-bit: CR7 LT at bit 28, GT at bit 29
+    // rlwinm r, r, 29, 31, 31 - extract LT from bit 28 to bit 31
+    SDValue LTOps[] = {MFOCRF, CurDAG->getTargetConstant(29, dl, MVT::i32),
                        CurDAG->getTargetConstant(31, dl, MVT::i32),
                        CurDAG->getTargetConstant(31, dl, MVT::i32)};
     LTBit =
         SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, LTOps), 0);
 
-    // Extract GT bit (bit 1 of CR7 -> rotate left 1, mask bit 31)
-    SDValue GTOps[] = {MFOCRF, CurDAG->getTargetConstant(1, dl, MVT::i32),
+    // rlwinm r, r, 30, 31, 31 - extract GT from bit 29 to bit 31
+    SDValue GTOps[] = {MFOCRF, CurDAG->getTargetConstant(30, dl, MVT::i32),
                        CurDAG->getTargetConstant(31, dl, MVT::i32),
                        CurDAG->getTargetConstant(31, dl, MVT::i32)};
     GTBit =
diff --git a/llvm/test/CodeGen/PowerPC/scmp.ll b/llvm/test/CodeGen/PowerPC/scmp.ll
index 14cf81536546f..d9fee31d2b7f1 100644
--- a/llvm/test/CodeGen/PowerPC/scmp.ll
+++ b/llvm/test/CodeGen/PowerPC/scmp.ll
@@ -4,10 +4,10 @@
 define i8 @scmp_8_8(i8 signext %x, i8 signext %y) nounwind {
 ; CHECK-LABEL: scmp_8_8:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    cmpw 3, 4
-; CHECK-NEXT:    mfocrf 3, 128
-; CHECK-NEXT:    srwi 4, 3, 31
-; CHECK-NEXT:    rlwinm 3, 3, 2, 31, 31
+; CHECK-NEXT:    cmpw 7, 3, 4
+; CHECK-NEXT:    mfocrf 3, 1
+; CHECK-NEXT:    rlwinm 4, 3, 30, 31, 31
+; CHECK-NEXT:    rlwinm 3, 3, 29, 31, 31
 ; CHECK-NEXT:    sub 3, 4, 3
 ; CHECK-NEXT:    blr
   %1 = call i8 @llvm.scmp(i8 %x, i8 %y)
@@ -17,10 +17,10 @@ define i8 @scmp_8_8(i8 signext %x, i8 signext %y) nounwind {
 define i8 @scmp_8_16(i16 signext %x, i16 signext %y) nounwind {
 ; CHECK-LABEL: scmp_8_16:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    cmpw 3, 4
-; CHECK-NEXT:    mfocrf 3, 128
-; CHECK-NEXT:    srwi 4, 3, 31
-; CHECK-NEXT:    rlwinm 3, 3, 2, 31, 31
+; CHECK-NEXT:    cmpw 7, 3, 4
+; CHECK-NEXT:    mfocrf 3, 1
+; CHECK-NEXT:    rlwinm 4, 3, 30, 31, 31
+; CHECK-NEXT:    rlwinm 3, 3, 29, 31, 31
 ; CHECK-NEXT:    sub 3, 4, 3
 ; CHECK-NEXT:    blr
   %1 = call i8 @llvm.scmp(i16 %x, i16 %y)
@@ -30,10 +30,10 @@ define i8 @scmp_8_16(i16 signext %x, i16 signext %y) nounwind {
 define i8 @scmp_8_32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: scmp_8_32:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    cmpw 3, 4
-; CHECK-NEXT:    mfocrf 3, 128
-; CHECK-NEXT:    srwi 4, 3, 31
-; CHECK-NEXT:    rlwinm 3, 3, 2, 31, 31
+; CHECK-NEXT:    cmpw 7, 3, 4
+; CHECK-NEXT:    mfocrf 3, 1
+; CHECK-NEXT:    rlwinm 4, 3, 30, 31, 31
+; CHECK-NEXT:    rlwinm 3, 3, 29, 31, 31
 ; CHECK-NEXT:    sub 3, 4, 3
 ; CHECK-NEXT:    blr
   %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
@@ -43,10 +43,10 @@ define i8 @scmp_8_32(i32 %x, i32 %y) nounwind {
 define i8 @scmp_8_64(i64 %x, i64 %y) nounwind {
 ; CHECK-LABEL: scmp_8_64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    cmpd 3, 4
-; CHECK-NEXT:    mfocrf 3, 128
-; CHECK-NEXT:    srwi 4, 3, 31
-; CHECK-NEXT:    rlwinm 3, 3, 2, 31, 31
+; CHECK-NEXT:    cmpd 7, 3, 4
+; CHECK-NEXT:    mfocrf 3, 1
+; CHECK-NEXT:    rlwinm 4, 3, 30, 31, 31
+; CHECK-NEXT:    rlwinm 3, 3, 29, 31, 31
 ; CHECK-NEXT:    sub 3, 4, 3
 ; CHECK-NEXT:    blr
   %1 = call i8 @llvm.scmp(i64 %x, i64 %y)
@@ -77,10 +77,10 @@ define i8 @scmp_8_128(i128 %x, i128 %y) nounwind {
 define i32 @scmp_32_32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: scmp_32_32:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    cmpw 3, 4
-; CHECK-NEXT:    mfocrf 3, 128
-; CHECK-NEXT:    srwi 4, 3, 31
-; CHECK-NEXT:    rlwinm 3, 3, 2, 31, 31
+; CHECK-NEXT:    cmpw 7, 3, 4
+; CHECK-NEXT:    mfocrf 3, 1
+; CHECK-NEXT:    rlwinm 4, 3, 30, 31, 31
+; CHECK-NEXT:    rlwinm 3, 3, 29, 31, 31
 ; CHECK-NEXT:    sub 3, 4, 3
 ; CHECK-NEXT:    blr
   %1 = call i32 @llvm.scmp(i32 %x, i32 %y)
@@ -90,10 +90,10 @@ define i32 @scmp_32_32(i32 %x, i32 %y) nounwind {
 define i32 @scmp_32_64(i64 %x, i64 %y) nounwind {
 ; CHECK-LABEL: scmp_32_64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    cmpd 3, 4
-; CHECK-NEXT:    mfocrf 3, 128
-; CHECK-NEXT:    srwi 4, 3, 31
-; CHECK-NEXT:    rlwinm 3, 3, 2, 31, 31
+; CHECK-NEXT:    cmpd 7, 3, 4
+; CHECK-NEXT:    mfocrf 3, 1
+; CHECK-NEXT:    rlwinm 4, 3, 30, 31, 31
+; CHECK-NEXT:    rlwinm 3, 3, 29, 31, 31
 ; CHECK-NEXT:    sub 3, 4, 3
 ; CHECK-NEXT:    blr
   %1 = call i32 @llvm.scmp(i64 %x, i64 %y)
@@ -103,8 +103,8 @@ define i32 @scmp_32_64(i64 %x, i64 %y) nounwind {
 define i64 @scmp_64_64(i64 %x, i64 %y) nounwind {
 ; CHECK-LABEL: scmp_64_64:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    cmpd 3, 4
-; CHECK-NEXT:    mfocrf 3, 128
+; CHECK-NEXT:    cmpd 7, 3, 4
+; CHECK-NEXT:    mfocrf 3, 1
 ; CHECK-NEXT:    rldicl 4, 3, 61, 63
 ; CHECK-NEXT:    rldicl 3, 3, 62, 63
 ; CHECK-NEXT:    sub 3, 4, 3

>From 4fc19f75b3e1b91d895b188697e2250ec077e239 Mon Sep 17 00:00:00 2001
From: zhijian <zhijian at ca.ibm.com>
Date: Mon, 1 Jun 2026 15:18:07 +0000
Subject: [PATCH 4/4] modify comment

---
 llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 24 +++++++++++++--------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index a5bdd640f1fae..b1a643d5ca1fb 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -4112,12 +4112,18 @@ bool PPCDAGToDAGISel::trySelectThreeWayCompare(SDNode *N) {
   if (LHS != InnerLHS || RHS != InnerRHS)
     return false;
 
-  // Pattern matched! Generate optimal code:
-  // cmpd/cmpw  LHS, RHS
-  // mfocrf RT, FXM
-  // rldicl/rlwinm LT, r, 62/2, 63/31  (extract LT bit)
-  // rldicl/rlwinm GT, r, 61/1, 63/31  (extract GT bit)
-  // subf result, GT, LT   (LT - GT = -1/0/1)
+  // For 64-bit:
+  //   cmpd       LHS, RHS
+  //   mfocrf8    r, CR7
+  //   rldicl     LT, r, 62, 63  (extract LT bit from CR7)
+  //   rldicl     GT, r, 61, 63  (extract GT bit from CR7)
+  //   subf8      result, LT, GT (GT - LT = -1/0/1)
+  // For 32-bit:
+  //   cmpw       LHS, RHS
+  //   mfocrf     r, CR7
+  //   rlwinm     LT, r, 29, 31, 31  (extract LT bit from CR7)
+  //   rlwinm     GT, r, 30, 31, 31  (extract GT bit from CR7)
+  //   subf       result, LT, GT     (GT - LT = -1/0/1)
 
   SDLoc dl(N);
   bool Is64BitCmp = (CmpVT == MVT::i64);
@@ -4175,9 +4181,9 @@ bool PPCDAGToDAGISel::trySelectThreeWayCompare(SDNode *N) {
   }
 
   // Compute result: GT - LT (match result type)
-  // If LT: 0 - 1 = -1 ✓
-  // If GT: 1 - 0 = 1 ✓
-  // If EQ: 0 - 0 = 0 ✓
+  // If LT: 0 - 1 = -1
+  // If GT: 1 - 0 = 1
+  // If EQ: 0 - 0 = 0
   unsigned SubOpc = Is64BitRes ? PPC::SUBF8 : PPC::SUBF;
   SDValue Result =
       SDValue(CurDAG->getMachineNode(SubOpc, dl, ResVT, LTBit, GTBit), 0);



More information about the llvm-commits mailing list