[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