[llvm] [InstCombine][SelectionDAG] Improve i128 signum codegen (PR #190787)

Takashi Idobe via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 8 18:02:37 PDT 2026


https://github.com/Takashiidobe updated https://github.com/llvm/llvm-project/pull/190787

>From 4687cb2fe9f63a05c5bc4380a0fd58c6b89e449f Mon Sep 17 00:00:00 2001
From: Takashiidobe <idobetakashi at gmail.com>
Date: Sun, 5 Apr 2026 11:44:28 -0400
Subject: [PATCH 1/8] improve scmp codegen for i128 which is used by rust's
 i128.signum

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 27 ++++++++++++++++
 llvm/test/CodeGen/X86/scmp.ll                 | 32 +++++++++++++++++++
 2 files changed, 59 insertions(+)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 383e45c5ea3a8..aa3332f59cbc6 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -15161,6 +15161,33 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
   if (SDValue Res = tryToFoldExtendOfConstant(N, DL, TLI, DAG, LegalTypes))
     return Res;
 
+  // fold (sext (scmp x, 0)) -> (or (sra x, bw-1), (zext (setne x, 0)))
+  // when the sext result type equals the scmp input type.
+  // This avoids the generic sub(IsGT,IsLT) expansion and the i8 round-trip,
+  // producing a sign-mask OR nonzero-flag sequence instead.
+  // fold (sext (scmp x, 0)) -> (or (sra x, bw-1), (zext (setne x, 0)))
+  // Valid for any sext result width: -1/0/1 in the input type truncates or
+  // sign-extends correctly to any wider or narrower integer type.
+  // This avoids the generic sub(IsGT,IsLT) expansion and the narrow round-trip
+  // through the scmp result type, producing a sign-mask OR nonzero-flag
+  // sequence in the input type instead.
+  if (N0.getOpcode() == ISD::SCMP && isNullConstant(N0.getOperand(1))) {
+    EVT InVT = N0.getOperand(0).getValueType();
+    if (InVT.isScalarInteger()) {
+      SDValue X = N0.getOperand(0);
+      SDValue ShiftAmt =
+          DAG.getConstant(InVT.getScalarSizeInBits() - 1, DL, InVT);
+      SDValue SignMask = DAG.getNode(ISD::SRA, DL, InVT, X, ShiftAmt);
+      EVT BoolVT =
+          TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), InVT);
+      SDValue IsNZ =
+          DAG.getSetCC(DL, BoolVT, X, DAG.getConstant(0, DL, InVT), ISD::SETNE);
+      SDValue IsNZExt = DAG.getZExtOrTrunc(IsNZ, DL, InVT);
+      SDValue Result = DAG.getNode(ISD::OR, DL, InVT, SignMask, IsNZExt);
+      return DAG.getSExtOrTrunc(Result, DL, VT);
+    }
+  }
+
   // fold (sext (sext x)) -> (sext x)
   // fold (sext (aext x)) -> (sext x)
   if (N0.getOpcode() == ISD::SIGN_EXTEND || N0.getOpcode() == ISD::ANY_EXTEND)
diff --git a/llvm/test/CodeGen/X86/scmp.ll b/llvm/test/CodeGen/X86/scmp.ll
index 393e05bfd0cc6..27cea4bb77d2e 100644
--- a/llvm/test/CodeGen/X86/scmp.ll
+++ b/llvm/test/CodeGen/X86/scmp.ll
@@ -3899,3 +3899,35 @@ define <2 x i16> @scmp_ret_wider_than_operands(<2 x i8> %x, <2 x i8> %y) nounwin
   ret <2 x i16> %1
 }
 
+
+; sext(scmp(x, 0)) where result type == input type folds to
+; or(sra(x, bw-1), zext(setne(x, 0))), avoiding the i8 round-trip.
+define i128 @sext_scmp_i128_zero(i128 %x) nounwind {
+; X64-LABEL: sext_scmp_i128_zero:
+; X64:       # %bb.0:
+; X64-NEXT:    movq %rsi, %rdx
+; X64-NEXT:    xorl %eax, %eax
+; X64-NEXT:    orq %rsi, %rdi
+; X64-NEXT:    setne %al
+; X64-NEXT:    sarq $63, %rdx
+; X64-NEXT:    orq %rdx, %rax
+; X64-NEXT:    retq
+  %cmp = call i8 @llvm.scmp.i8.i128(i128 %x, i128 0)
+  %ext = sext i8 %cmp to i128
+  ret i128 %ext
+}
+
+; sext to a narrower width also folds: compute in input type, truncate down.
+define i64 @sext_scmp_i128_to_i64(i128 %x) nounwind {
+; X64-LABEL: sext_scmp_i128_to_i64:
+; X64:       # %bb.0:
+; X64-NEXT:    xorl %eax, %eax
+; X64-NEXT:    orq %rsi, %rdi
+; X64-NEXT:    setne %al
+; X64-NEXT:    sarq $63, %rsi
+; X64-NEXT:    orq %rsi, %rax
+; X64-NEXT:    retq
+  %cmp = call i8 @llvm.scmp.i8.i128(i128 %x, i128 0)
+  %ext = sext i8 %cmp to i64
+  ret i64 %ext
+}

>From 20d25c61328068cf532d81f98b6baa6961f27b1c Mon Sep 17 00:00:00 2001
From: Takashiidobe <idobetakashi at gmail.com>
Date: Sun, 5 Apr 2026 12:31:26 -0400
Subject: [PATCH 2/8] handle the plain no sext case

---
 .../CodeGen/SelectionDAG/TargetLowering.cpp   |  14 ++
 llvm/test/CodeGen/X86/scmp.ll                 | 140 ++++++++++++++++++
 2 files changed, 154 insertions(+)

diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 092bc283c84dc..9c032722537b8 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -11479,6 +11479,20 @@ SDValue TargetLowering::expandCMP(SDNode *Node, SelectionDAG &DAG) const {
   EVT BoolVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
   SDLoc dl(Node);
 
+  // fold scmp(x, 0) -> or(sra(x, bw-1), zext(setne(x, 0)))
+  // This is cheaper than the generic sub(IsGT, IsLT) expansion for wide
+  // integers: the sign mask comes from a single arithmetic shift and the
+  // nonzero test is a single comparison, with no flag-chain dependencies
+  // between them.
+  if (Opcode == ISD::SCMP && isNullConstant(RHS) && VT.isScalarInteger()) {
+    SDValue ShiftAmt = DAG.getConstant(VT.getScalarSizeInBits() - 1, dl, VT);
+    SDValue SignMask = DAG.getNode(ISD::SRA, dl, VT, LHS, ShiftAmt);
+    SDValue IsNZ = DAG.getSetCC(dl, BoolVT, LHS, RHS, ISD::SETNE);
+    SDValue IsNZExt = DAG.getZExtOrTrunc(IsNZ, dl, VT);
+    SDValue Result = DAG.getNode(ISD::OR, dl, VT, SignMask, IsNZExt);
+    return DAG.getSExtOrTrunc(Result, dl, ResVT);
+  }
+
   auto LTPredicate = (Opcode == ISD::UCMP ? ISD::SETULT : ISD::SETLT);
   auto GTPredicate = (Opcode == ISD::UCMP ? ISD::SETUGT : ISD::SETGT);
   SDValue IsLT = DAG.getSetCC(dl, BoolVT, LHS, RHS, LTPredicate);
diff --git a/llvm/test/CodeGen/X86/scmp.ll b/llvm/test/CodeGen/X86/scmp.ll
index 27cea4bb77d2e..be0d57b4cc44b 100644
--- a/llvm/test/CodeGen/X86/scmp.ll
+++ b/llvm/test/CodeGen/X86/scmp.ll
@@ -3912,6 +3912,52 @@ define i128 @sext_scmp_i128_zero(i128 %x) nounwind {
 ; X64-NEXT:    sarq $63, %rdx
 ; X64-NEXT:    orq %rdx, %rax
 ; X64-NEXT:    retq
+;
+; X86-LABEL: sext_scmp_i128_zero:
+; X86:       # %bb.0:
+; X86-NEXT:    pushl %ebp
+; X86-NEXT:    movl %esp, %ebp
+; X86-NEXT:    pushl %edi
+; X86-NEXT:    pushl %esi
+; X86-NEXT:    andl $-16, %esp
+; X86-NEXT:    movl 8(%ebp), %eax
+; X86-NEXT:    movl 24(%ebp), %esi
+; X86-NEXT:    movl 36(%ebp), %ecx
+; X86-NEXT:    movl 28(%ebp), %edi
+; X86-NEXT:    orl %ecx, %edi
+; X86-NEXT:    orl 32(%ebp), %esi
+; X86-NEXT:    xorl %edx, %edx
+; X86-NEXT:    orl %edi, %esi
+; X86-NEXT:    setne %dl
+; X86-NEXT:    sarl $31, %ecx
+; X86-NEXT:    orl %ecx, %edx
+; X86-NEXT:    movl %ecx, 12(%eax)
+; X86-NEXT:    movl %ecx, 8(%eax)
+; X86-NEXT:    movl %ecx, 4(%eax)
+; X86-NEXT:    movl %edx, (%eax)
+; X86-NEXT:    leal -8(%ebp), %esp
+; X86-NEXT:    popl %esi
+; X86-NEXT:    popl %edi
+; X86-NEXT:    popl %ebp
+; X86-NEXT:    retl $4
+;
+; SETZUCC-LABEL: sext_scmp_i128_zero:
+; SETZUCC:       # %bb.0:
+; SETZUCC-NEXT:    movq %rsi, %rdx
+; SETZUCC-NEXT:    orq %rsi, %rdi
+; SETZUCC-NEXT:    setzune %al
+; SETZUCC-NEXT:    sarq $63, %rdx
+; SETZUCC-NEXT:    orq %rdx, %rax
+; SETZUCC-NEXT:    retq
+;
+; NO-SETZUCC-LABEL: sext_scmp_i128_zero:
+; NO-SETZUCC:       # %bb.0:
+; NO-SETZUCC-NEXT:    movq %rsi, %rdx
+; NO-SETZUCC-NEXT:    orq %rsi, %rdi
+; NO-SETZUCC-NEXT:    setzune %al
+; NO-SETZUCC-NEXT:    sarq $63, %rdx
+; NO-SETZUCC-NEXT:    orq %rdx, %rax
+; NO-SETZUCC-NEXT:    retq
   %cmp = call i8 @llvm.scmp.i8.i128(i128 %x, i128 0)
   %ext = sext i8 %cmp to i128
   ret i128 %ext
@@ -3927,7 +3973,101 @@ define i64 @sext_scmp_i128_to_i64(i128 %x) nounwind {
 ; X64-NEXT:    sarq $63, %rsi
 ; X64-NEXT:    orq %rsi, %rax
 ; X64-NEXT:    retq
+;
+; X86-LABEL: sext_scmp_i128_to_i64:
+; X86:       # %bb.0:
+; X86-NEXT:    pushl %ebp
+; X86-NEXT:    movl %esp, %ebp
+; X86-NEXT:    pushl %esi
+; X86-NEXT:    andl $-16, %esp
+; X86-NEXT:    subl $16, %esp
+; X86-NEXT:    movl 8(%ebp), %ecx
+; X86-NEXT:    movl 20(%ebp), %edx
+; X86-NEXT:    movl 12(%ebp), %esi
+; X86-NEXT:    orl %edx, %esi
+; X86-NEXT:    orl 16(%ebp), %ecx
+; X86-NEXT:    xorl %eax, %eax
+; X86-NEXT:    orl %esi, %ecx
+; X86-NEXT:    setne %al
+; X86-NEXT:    sarl $31, %edx
+; X86-NEXT:    orl %edx, %eax
+; X86-NEXT:    leal -4(%ebp), %esp
+; X86-NEXT:    popl %esi
+; X86-NEXT:    popl %ebp
+; X86-NEXT:    retl
+;
+; SETZUCC-LABEL: sext_scmp_i128_to_i64:
+; SETZUCC:       # %bb.0:
+; SETZUCC-NEXT:    orq %rsi, %rdi
+; SETZUCC-NEXT:    setzune %al
+; SETZUCC-NEXT:    sarq $63, %rsi
+; SETZUCC-NEXT:    orq %rsi, %rax
+; SETZUCC-NEXT:    retq
+;
+; NO-SETZUCC-LABEL: sext_scmp_i128_to_i64:
+; NO-SETZUCC:       # %bb.0:
+; NO-SETZUCC-NEXT:    orq %rsi, %rdi
+; NO-SETZUCC-NEXT:    setzune %al
+; NO-SETZUCC-NEXT:    sarq $63, %rsi
+; NO-SETZUCC-NEXT:    orq %rsi, %rax
+; NO-SETZUCC-NEXT:    retq
   %cmp = call i8 @llvm.scmp.i8.i128(i128 %x, i128 0)
   %ext = sext i8 %cmp to i64
   ret i64 %ext
 }
+
+; bare scmp(x, 0) returning narrow type folds via expandCMP.
+define i8 @scmp_i128_zero_to_i8(i128 %x) nounwind {
+; X64-LABEL: scmp_i128_zero_to_i8:
+; X64:       # %bb.0:
+; X64-NEXT:    xorl %eax, %eax
+; X64-NEXT:    orq %rsi, %rdi
+; X64-NEXT:    setne %al
+; X64-NEXT:    sarq $63, %rsi
+; X64-NEXT:    orl %esi, %eax
+; X64-NEXT:    # kill: def $al killed $al killed $eax
+; X64-NEXT:    retq
+;
+; X86-LABEL: scmp_i128_zero_to_i8:
+; X86:       # %bb.0:
+; X86-NEXT:    pushl %ebp
+; X86-NEXT:    movl %esp, %ebp
+; X86-NEXT:    pushl %esi
+; X86-NEXT:    andl $-16, %esp
+; X86-NEXT:    subl $16, %esp
+; X86-NEXT:    movl 8(%ebp), %edx
+; X86-NEXT:    movl 20(%ebp), %eax
+; X86-NEXT:    movl 12(%ebp), %esi
+; X86-NEXT:    orl %eax, %esi
+; X86-NEXT:    orl 16(%ebp), %edx
+; X86-NEXT:    xorl %ecx, %ecx
+; X86-NEXT:    orl %esi, %edx
+; X86-NEXT:    setne %cl
+; X86-NEXT:    sarl $31, %eax
+; X86-NEXT:    orl %ecx, %eax
+; X86-NEXT:    # kill: def $al killed $al killed $eax
+; X86-NEXT:    leal -4(%ebp), %esp
+; X86-NEXT:    popl %esi
+; X86-NEXT:    popl %ebp
+; X86-NEXT:    retl
+;
+; SETZUCC-LABEL: scmp_i128_zero_to_i8:
+; SETZUCC:       # %bb.0:
+; SETZUCC-NEXT:    orq %rsi, %rdi
+; SETZUCC-NEXT:    setzune %al
+; SETZUCC-NEXT:    sarq $63, %rsi
+; SETZUCC-NEXT:    orl %esi, %eax
+; SETZUCC-NEXT:    # kill: def $al killed $al killed $eax
+; SETZUCC-NEXT:    retq
+;
+; NO-SETZUCC-LABEL: scmp_i128_zero_to_i8:
+; NO-SETZUCC:       # %bb.0:
+; NO-SETZUCC-NEXT:    orq %rsi, %rdi
+; NO-SETZUCC-NEXT:    setzune %al
+; NO-SETZUCC-NEXT:    sarq $63, %rsi
+; NO-SETZUCC-NEXT:    orl %esi, %eax
+; NO-SETZUCC-NEXT:    # kill: def $al killed $al killed $eax
+; NO-SETZUCC-NEXT:    retq
+  %r = call i8 @llvm.scmp.i8.i128(i128 %x, i128 0)
+  ret i8 %r
+}

>From 5537cf74f7cde4abe904bc31609f787ad2396d42 Mon Sep 17 00:00:00 2001
From: Takashiidobe <idobetakashi at gmail.com>
Date: Sun, 5 Apr 2026 12:38:33 -0400
Subject: [PATCH 3/8] remove the visitSIGN_EXTEND fold since it's not necessary
 in this case

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 27 -------------------
 llvm/test/CodeGen/X86/scmp.ll                 |  9 ++++---
 2 files changed, 6 insertions(+), 30 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index aa3332f59cbc6..383e45c5ea3a8 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -15161,33 +15161,6 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
   if (SDValue Res = tryToFoldExtendOfConstant(N, DL, TLI, DAG, LegalTypes))
     return Res;
 
-  // fold (sext (scmp x, 0)) -> (or (sra x, bw-1), (zext (setne x, 0)))
-  // when the sext result type equals the scmp input type.
-  // This avoids the generic sub(IsGT,IsLT) expansion and the i8 round-trip,
-  // producing a sign-mask OR nonzero-flag sequence instead.
-  // fold (sext (scmp x, 0)) -> (or (sra x, bw-1), (zext (setne x, 0)))
-  // Valid for any sext result width: -1/0/1 in the input type truncates or
-  // sign-extends correctly to any wider or narrower integer type.
-  // This avoids the generic sub(IsGT,IsLT) expansion and the narrow round-trip
-  // through the scmp result type, producing a sign-mask OR nonzero-flag
-  // sequence in the input type instead.
-  if (N0.getOpcode() == ISD::SCMP && isNullConstant(N0.getOperand(1))) {
-    EVT InVT = N0.getOperand(0).getValueType();
-    if (InVT.isScalarInteger()) {
-      SDValue X = N0.getOperand(0);
-      SDValue ShiftAmt =
-          DAG.getConstant(InVT.getScalarSizeInBits() - 1, DL, InVT);
-      SDValue SignMask = DAG.getNode(ISD::SRA, DL, InVT, X, ShiftAmt);
-      EVT BoolVT =
-          TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), InVT);
-      SDValue IsNZ =
-          DAG.getSetCC(DL, BoolVT, X, DAG.getConstant(0, DL, InVT), ISD::SETNE);
-      SDValue IsNZExt = DAG.getZExtOrTrunc(IsNZ, DL, InVT);
-      SDValue Result = DAG.getNode(ISD::OR, DL, InVT, SignMask, IsNZExt);
-      return DAG.getSExtOrTrunc(Result, DL, VT);
-    }
-  }
-
   // fold (sext (sext x)) -> (sext x)
   // fold (sext (aext x)) -> (sext x)
   if (N0.getOpcode() == ISD::SIGN_EXTEND || N0.getOpcode() == ISD::ANY_EXTEND)
diff --git a/llvm/test/CodeGen/X86/scmp.ll b/llvm/test/CodeGen/X86/scmp.ll
index be0d57b4cc44b..4ca437476d025 100644
--- a/llvm/test/CodeGen/X86/scmp.ll
+++ b/llvm/test/CodeGen/X86/scmp.ll
@@ -3971,7 +3971,8 @@ define i64 @sext_scmp_i128_to_i64(i128 %x) nounwind {
 ; X64-NEXT:    orq %rsi, %rdi
 ; X64-NEXT:    setne %al
 ; X64-NEXT:    sarq $63, %rsi
-; X64-NEXT:    orq %rsi, %rax
+; X64-NEXT:    orl %eax, %esi
+; X64-NEXT:    movsbq %sil, %rax
 ; X64-NEXT:    retq
 ;
 ; X86-LABEL: sext_scmp_i128_to_i64:
@@ -4001,7 +4002,8 @@ define i64 @sext_scmp_i128_to_i64(i128 %x) nounwind {
 ; SETZUCC-NEXT:    orq %rsi, %rdi
 ; SETZUCC-NEXT:    setzune %al
 ; SETZUCC-NEXT:    sarq $63, %rsi
-; SETZUCC-NEXT:    orq %rsi, %rax
+; SETZUCC-NEXT:    orl %eax, %esi
+; SETZUCC-NEXT:    movsbq %sil, %rax
 ; SETZUCC-NEXT:    retq
 ;
 ; NO-SETZUCC-LABEL: sext_scmp_i128_to_i64:
@@ -4009,7 +4011,8 @@ define i64 @sext_scmp_i128_to_i64(i128 %x) nounwind {
 ; NO-SETZUCC-NEXT:    orq %rsi, %rdi
 ; NO-SETZUCC-NEXT:    setzune %al
 ; NO-SETZUCC-NEXT:    sarq $63, %rsi
-; NO-SETZUCC-NEXT:    orq %rsi, %rax
+; NO-SETZUCC-NEXT:    orl %eax, %esi
+; NO-SETZUCC-NEXT:    movsbq %sil, %rax
 ; NO-SETZUCC-NEXT:    retq
   %cmp = call i8 @llvm.scmp.i8.i128(i128 %x, i128 0)
   %ext = sext i8 %cmp to i64

>From cb9de3f7584b1aaebb32e0276a0717d17fef5625 Mon Sep 17 00:00:00 2001
From: Takashiidobe <idobetakashi at gmail.com>
Date: Tue, 7 Apr 2026 08:28:26 -0400
Subject: [PATCH 4/8] refactor sext(scmp(x, 0)) fold into own function and
 clean up scmp tests by adding a new prefix to zu mattr'd tests to fold those
 cases

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp |  31 +++
 llvm/test/CodeGen/X86/scmp.ll                 | 248 ++++++------------
 2 files changed, 112 insertions(+), 167 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 383e45c5ea3a8..393fe841d1326 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -15145,6 +15145,34 @@ SDValue DAGCombiner::foldSextSetcc(SDNode *N) {
   return SDValue();
 }
 
+// fold sext(scmp(x, 0)) -> or(sra(x, bw-1)), zext(setne(x, 0))
+// Valid for any sext result width: -1/0/1 in the input type truncates or
+// sign-extends correctly to any wider or narrower integer type.
+// This avoids the generic sub(IsGT,IsLT) expansion and the narrow round-trip
+// through the scmp result type, producing a sign-mask OR nonzero-flag
+// sequence in the input type instead.
+static SDValue tryToFoldSExtOfSCMP(SDNode *N, const SDLoc &DL,
+                                   const TargetLowering &TLI,
+                                   SelectionDAG &DAG) {
+  SDValue N0 = N->getOperand(0);
+  EVT VT = N->getValueType(0);
+  if (N0.getOpcode() != ISD::SCMP || !isNullConstant(N0.getOperand(1)))
+    return SDValue();
+  EVT InVT = N0.getOperand(0).getValueType();
+  if (!InVT.isScalarInteger())
+    return SDValue();
+  SDValue X = N0.getOperand(0);
+  SDValue ShiftAmt = DAG.getConstant(InVT.getScalarSizeInBits() - 1, DL, InVT);
+  SDValue SignMask = DAG.getNode(ISD::SRA, DL, InVT, X, ShiftAmt);
+  EVT BoolVT =
+      TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), InVT);
+  SDValue IsNZ =
+      DAG.getSetCC(DL, BoolVT, X, DAG.getConstant(0, DL, InVT), ISD::SETNE);
+  SDValue IsNZExt = DAG.getZExtOrTrunc(IsNZ, DL, InVT);
+  SDValue Result = DAG.getNode(ISD::OR, DL, InVT, SignMask, IsNZExt);
+  return DAG.getSExtOrTrunc(Result, DL, VT);
+}
+
 SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
   SDValue N0 = N->getOperand(0);
   EVT VT = N->getValueType(0);
@@ -15161,6 +15189,9 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
   if (SDValue Res = tryToFoldExtendOfConstant(N, DL, TLI, DAG, LegalTypes))
     return Res;
 
+  if (SDValue Res = tryToFoldSExtOfSCMP(N, DL, TLI, DAG))
+    return Res;
+
   // fold (sext (sext x)) -> (sext x)
   // fold (sext (aext x)) -> (sext x)
   if (N0.getOpcode() == ISD::SIGN_EXTEND || N0.getOpcode() == ISD::ANY_EXTEND)
diff --git a/llvm/test/CodeGen/X86/scmp.ll b/llvm/test/CodeGen/X86/scmp.ll
index 4ca437476d025..17ec6a7858795 100644
--- a/llvm/test/CodeGen/X86/scmp.ll
+++ b/llvm/test/CodeGen/X86/scmp.ll
@@ -4,8 +4,8 @@
 ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mcpu=x86-64-v3 | FileCheck %s --check-prefixes=X64,AVX,AVX2
 ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mcpu=x86-64-v4 | FileCheck %s --check-prefixes=X64,AVX,AVX512
 ; RUN: llc < %s -mtriple=i686-unknown-unknown | FileCheck %s --check-prefix=X86
-; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+zu | FileCheck %s --check-prefixes=SSE,SETZUCC
-; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+zu,+prefer-legacy-setcc | FileCheck %s --check-prefixes=SSE,NO-SETZUCC
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+zu | FileCheck %s --check-prefixes=SSE,ZU,SETZUCC
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+zu,+prefer-legacy-setcc | FileCheck %s --check-prefixes=SSE,ZU,NO-SETZUCC
 
 define i8 @scmp.8.8(i8 %x, i8 %y) nounwind {
 ; X64-LABEL: scmp.8.8:
@@ -1105,35 +1105,20 @@ define <4 x i32> @scmp_narrow_vec_op(<4 x i8> %x, <4 x i8> %y) nounwind {
 ; X86-NEXT:    popl %ebx
 ; X86-NEXT:    retl $4
 ;
-; SETZUCC-LABEL: scmp_narrow_vec_op:
-; SETZUCC:       # %bb.0:
-; SETZUCC-NEXT:    punpcklbw {{.*#+}} xmm1 = xmm1[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
-; SETZUCC-NEXT:    punpcklwd {{.*#+}} xmm1 = xmm1[0,0,1,1,2,2,3,3]
-; SETZUCC-NEXT:    psrad $24, %xmm1
-; SETZUCC-NEXT:    punpcklbw {{.*#+}} xmm0 = xmm0[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
-; SETZUCC-NEXT:    punpcklwd {{.*#+}} xmm0 = xmm0[0,0,1,1,2,2,3,3]
-; SETZUCC-NEXT:    psrad $24, %xmm0
-; SETZUCC-NEXT:    movdqa %xmm0, %xmm2
-; SETZUCC-NEXT:    pcmpgtd %xmm1, %xmm2
-; SETZUCC-NEXT:    pcmpgtd %xmm0, %xmm1
-; SETZUCC-NEXT:    psubd %xmm2, %xmm1
-; SETZUCC-NEXT:    movdqa %xmm1, %xmm0
-; SETZUCC-NEXT:    retq
-;
-; NO-SETZUCC-LABEL: scmp_narrow_vec_op:
-; NO-SETZUCC:       # %bb.0:
-; NO-SETZUCC-NEXT:    punpcklbw {{.*#+}} xmm1 = xmm1[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
-; NO-SETZUCC-NEXT:    punpcklwd {{.*#+}} xmm1 = xmm1[0,0,1,1,2,2,3,3]
-; NO-SETZUCC-NEXT:    psrad $24, %xmm1
-; NO-SETZUCC-NEXT:    punpcklbw {{.*#+}} xmm0 = xmm0[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
-; NO-SETZUCC-NEXT:    punpcklwd {{.*#+}} xmm0 = xmm0[0,0,1,1,2,2,3,3]
-; NO-SETZUCC-NEXT:    psrad $24, %xmm0
-; NO-SETZUCC-NEXT:    movdqa %xmm0, %xmm2
-; NO-SETZUCC-NEXT:    pcmpgtd %xmm1, %xmm2
-; NO-SETZUCC-NEXT:    pcmpgtd %xmm0, %xmm1
-; NO-SETZUCC-NEXT:    psubd %xmm2, %xmm1
-; NO-SETZUCC-NEXT:    movdqa %xmm1, %xmm0
-; NO-SETZUCC-NEXT:    retq
+; ZU-LABEL: scmp_narrow_vec_op:
+; ZU:       # %bb.0:
+; ZU-NEXT:    punpcklbw {{.*#+}} xmm1 = xmm1[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
+; ZU-NEXT:    punpcklwd {{.*#+}} xmm1 = xmm1[0,0,1,1,2,2,3,3]
+; ZU-NEXT:    psrad $24, %xmm1
+; ZU-NEXT:    punpcklbw {{.*#+}} xmm0 = xmm0[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
+; ZU-NEXT:    punpcklwd {{.*#+}} xmm0 = xmm0[0,0,1,1,2,2,3,3]
+; ZU-NEXT:    psrad $24, %xmm0
+; ZU-NEXT:    movdqa %xmm0, %xmm2
+; ZU-NEXT:    pcmpgtd %xmm1, %xmm2
+; ZU-NEXT:    pcmpgtd %xmm0, %xmm1
+; ZU-NEXT:    psubd %xmm2, %xmm1
+; ZU-NEXT:    movdqa %xmm1, %xmm0
+; ZU-NEXT:    retq
   %1 = call <4 x i32> @llvm.scmp(<4 x i8> %x, <4 x i8> %y)
   ret <4 x i32> %1
 }
@@ -1381,89 +1366,47 @@ define <16 x i32> @scmp_wide_vec_result(<16 x i8> %x, <16 x i8> %y) nounwind {
 ; X86-NEXT:    popl %ebp
 ; X86-NEXT:    retl $4
 ;
-; SETZUCC-LABEL: scmp_wide_vec_result:
-; SETZUCC:       # %bb.0:
-; SETZUCC-NEXT:    movdqa %xmm1, %xmm2
-; SETZUCC-NEXT:    movdqa %xmm0, %xmm3
-; SETZUCC-NEXT:    punpcklbw {{.*#+}} xmm1 = xmm1[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
-; SETZUCC-NEXT:    punpcklwd {{.*#+}} xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1],xmm0[2],xmm1[2],xmm0[3],xmm1[3]
-; SETZUCC-NEXT:    psrad $24, %xmm0
-; SETZUCC-NEXT:    punpcklbw {{.*#+}} xmm4 = xmm4[0],xmm3[0],xmm4[1],xmm3[1],xmm4[2],xmm3[2],xmm4[3],xmm3[3],xmm4[4],xmm3[4],xmm4[5],xmm3[5],xmm4[6],xmm3[6],xmm4[7],xmm3[7]
-; SETZUCC-NEXT:    punpcklwd {{.*#+}} xmm5 = xmm5[0],xmm4[0],xmm5[1],xmm4[1],xmm5[2],xmm4[2],xmm5[3],xmm4[3]
-; SETZUCC-NEXT:    psrad $24, %xmm5
-; SETZUCC-NEXT:    movdqa %xmm5, %xmm6
-; SETZUCC-NEXT:    pcmpgtd %xmm0, %xmm6
-; SETZUCC-NEXT:    pcmpgtd %xmm5, %xmm0
-; SETZUCC-NEXT:    psubd %xmm6, %xmm0
-; SETZUCC-NEXT:    punpckhwd {{.*#+}} xmm1 = xmm1[4,4,5,5,6,6,7,7]
-; SETZUCC-NEXT:    psrad $24, %xmm1
-; SETZUCC-NEXT:    punpckhwd {{.*#+}} xmm4 = xmm4[4,4,5,5,6,6,7,7]
-; SETZUCC-NEXT:    psrad $24, %xmm4
-; SETZUCC-NEXT:    movdqa %xmm4, %xmm5
-; SETZUCC-NEXT:    pcmpgtd %xmm1, %xmm5
-; SETZUCC-NEXT:    pcmpgtd %xmm4, %xmm1
-; SETZUCC-NEXT:    psubd %xmm5, %xmm1
-; SETZUCC-NEXT:    punpckhbw {{.*#+}} xmm4 = xmm4[8],xmm2[8],xmm4[9],xmm2[9],xmm4[10],xmm2[10],xmm4[11],xmm2[11],xmm4[12],xmm2[12],xmm4[13],xmm2[13],xmm4[14],xmm2[14],xmm4[15],xmm2[15]
-; SETZUCC-NEXT:    punpcklwd {{.*#+}} xmm2 = xmm2[0],xmm4[0],xmm2[1],xmm4[1],xmm2[2],xmm4[2],xmm2[3],xmm4[3]
-; SETZUCC-NEXT:    psrad $24, %xmm2
-; SETZUCC-NEXT:    punpckhbw {{.*#+}} xmm5 = xmm5[8],xmm3[8],xmm5[9],xmm3[9],xmm5[10],xmm3[10],xmm5[11],xmm3[11],xmm5[12],xmm3[12],xmm5[13],xmm3[13],xmm5[14],xmm3[14],xmm5[15],xmm3[15]
-; SETZUCC-NEXT:    punpcklwd {{.*#+}} xmm3 = xmm3[0],xmm5[0],xmm3[1],xmm5[1],xmm3[2],xmm5[2],xmm3[3],xmm5[3]
-; SETZUCC-NEXT:    psrad $24, %xmm3
-; SETZUCC-NEXT:    movdqa %xmm3, %xmm6
-; SETZUCC-NEXT:    pcmpgtd %xmm2, %xmm6
-; SETZUCC-NEXT:    pcmpgtd %xmm3, %xmm2
-; SETZUCC-NEXT:    psubd %xmm6, %xmm2
-; SETZUCC-NEXT:    punpckhwd {{.*#+}} xmm3 = xmm3[4],xmm4[4],xmm3[5],xmm4[5],xmm3[6],xmm4[6],xmm3[7],xmm4[7]
-; SETZUCC-NEXT:    psrad $24, %xmm3
-; SETZUCC-NEXT:    punpckhwd {{.*#+}} xmm4 = xmm4[4],xmm5[4],xmm4[5],xmm5[5],xmm4[6],xmm5[6],xmm4[7],xmm5[7]
-; SETZUCC-NEXT:    psrad $24, %xmm4
-; SETZUCC-NEXT:    movdqa %xmm4, %xmm5
-; SETZUCC-NEXT:    pcmpgtd %xmm3, %xmm5
-; SETZUCC-NEXT:    pcmpgtd %xmm4, %xmm3
-; SETZUCC-NEXT:    psubd %xmm5, %xmm3
-; SETZUCC-NEXT:    retq
-;
-; NO-SETZUCC-LABEL: scmp_wide_vec_result:
-; NO-SETZUCC:       # %bb.0:
-; NO-SETZUCC-NEXT:    movdqa %xmm1, %xmm2
-; NO-SETZUCC-NEXT:    movdqa %xmm0, %xmm3
-; NO-SETZUCC-NEXT:    punpcklbw {{.*#+}} xmm1 = xmm1[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
-; NO-SETZUCC-NEXT:    punpcklwd {{.*#+}} xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1],xmm0[2],xmm1[2],xmm0[3],xmm1[3]
-; NO-SETZUCC-NEXT:    psrad $24, %xmm0
-; NO-SETZUCC-NEXT:    punpcklbw {{.*#+}} xmm4 = xmm4[0],xmm3[0],xmm4[1],xmm3[1],xmm4[2],xmm3[2],xmm4[3],xmm3[3],xmm4[4],xmm3[4],xmm4[5],xmm3[5],xmm4[6],xmm3[6],xmm4[7],xmm3[7]
-; NO-SETZUCC-NEXT:    punpcklwd {{.*#+}} xmm5 = xmm5[0],xmm4[0],xmm5[1],xmm4[1],xmm5[2],xmm4[2],xmm5[3],xmm4[3]
-; NO-SETZUCC-NEXT:    psrad $24, %xmm5
-; NO-SETZUCC-NEXT:    movdqa %xmm5, %xmm6
-; NO-SETZUCC-NEXT:    pcmpgtd %xmm0, %xmm6
-; NO-SETZUCC-NEXT:    pcmpgtd %xmm5, %xmm0
-; NO-SETZUCC-NEXT:    psubd %xmm6, %xmm0
-; NO-SETZUCC-NEXT:    punpckhwd {{.*#+}} xmm1 = xmm1[4,4,5,5,6,6,7,7]
-; NO-SETZUCC-NEXT:    psrad $24, %xmm1
-; NO-SETZUCC-NEXT:    punpckhwd {{.*#+}} xmm4 = xmm4[4,4,5,5,6,6,7,7]
-; NO-SETZUCC-NEXT:    psrad $24, %xmm4
-; NO-SETZUCC-NEXT:    movdqa %xmm4, %xmm5
-; NO-SETZUCC-NEXT:    pcmpgtd %xmm1, %xmm5
-; NO-SETZUCC-NEXT:    pcmpgtd %xmm4, %xmm1
-; NO-SETZUCC-NEXT:    psubd %xmm5, %xmm1
-; NO-SETZUCC-NEXT:    punpckhbw {{.*#+}} xmm4 = xmm4[8],xmm2[8],xmm4[9],xmm2[9],xmm4[10],xmm2[10],xmm4[11],xmm2[11],xmm4[12],xmm2[12],xmm4[13],xmm2[13],xmm4[14],xmm2[14],xmm4[15],xmm2[15]
-; NO-SETZUCC-NEXT:    punpcklwd {{.*#+}} xmm2 = xmm2[0],xmm4[0],xmm2[1],xmm4[1],xmm2[2],xmm4[2],xmm2[3],xmm4[3]
-; NO-SETZUCC-NEXT:    psrad $24, %xmm2
-; NO-SETZUCC-NEXT:    punpckhbw {{.*#+}} xmm5 = xmm5[8],xmm3[8],xmm5[9],xmm3[9],xmm5[10],xmm3[10],xmm5[11],xmm3[11],xmm5[12],xmm3[12],xmm5[13],xmm3[13],xmm5[14],xmm3[14],xmm5[15],xmm3[15]
-; NO-SETZUCC-NEXT:    punpcklwd {{.*#+}} xmm3 = xmm3[0],xmm5[0],xmm3[1],xmm5[1],xmm3[2],xmm5[2],xmm3[3],xmm5[3]
-; NO-SETZUCC-NEXT:    psrad $24, %xmm3
-; NO-SETZUCC-NEXT:    movdqa %xmm3, %xmm6
-; NO-SETZUCC-NEXT:    pcmpgtd %xmm2, %xmm6
-; NO-SETZUCC-NEXT:    pcmpgtd %xmm3, %xmm2
-; NO-SETZUCC-NEXT:    psubd %xmm6, %xmm2
-; NO-SETZUCC-NEXT:    punpckhwd {{.*#+}} xmm3 = xmm3[4],xmm4[4],xmm3[5],xmm4[5],xmm3[6],xmm4[6],xmm3[7],xmm4[7]
-; NO-SETZUCC-NEXT:    psrad $24, %xmm3
-; NO-SETZUCC-NEXT:    punpckhwd {{.*#+}} xmm4 = xmm4[4],xmm5[4],xmm4[5],xmm5[5],xmm4[6],xmm5[6],xmm4[7],xmm5[7]
-; NO-SETZUCC-NEXT:    psrad $24, %xmm4
-; NO-SETZUCC-NEXT:    movdqa %xmm4, %xmm5
-; NO-SETZUCC-NEXT:    pcmpgtd %xmm3, %xmm5
-; NO-SETZUCC-NEXT:    pcmpgtd %xmm4, %xmm3
-; NO-SETZUCC-NEXT:    psubd %xmm5, %xmm3
-; NO-SETZUCC-NEXT:    retq
+; ZU-LABEL: scmp_wide_vec_result:
+; ZU:       # %bb.0:
+; ZU-NEXT:    movdqa %xmm1, %xmm2
+; ZU-NEXT:    movdqa %xmm0, %xmm3
+; ZU-NEXT:    punpcklbw {{.*#+}} xmm1 = xmm1[0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7]
+; ZU-NEXT:    punpcklwd {{.*#+}} xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1],xmm0[2],xmm1[2],xmm0[3],xmm1[3]
+; ZU-NEXT:    psrad $24, %xmm0
+; ZU-NEXT:    punpcklbw {{.*#+}} xmm4 = xmm4[0],xmm3[0],xmm4[1],xmm3[1],xmm4[2],xmm3[2],xmm4[3],xmm3[3],xmm4[4],xmm3[4],xmm4[5],xmm3[5],xmm4[6],xmm3[6],xmm4[7],xmm3[7]
+; ZU-NEXT:    punpcklwd {{.*#+}} xmm5 = xmm5[0],xmm4[0],xmm5[1],xmm4[1],xmm5[2],xmm4[2],xmm5[3],xmm4[3]
+; ZU-NEXT:    psrad $24, %xmm5
+; ZU-NEXT:    movdqa %xmm5, %xmm6
+; ZU-NEXT:    pcmpgtd %xmm0, %xmm6
+; ZU-NEXT:    pcmpgtd %xmm5, %xmm0
+; ZU-NEXT:    psubd %xmm6, %xmm0
+; ZU-NEXT:    punpckhwd {{.*#+}} xmm1 = xmm1[4,4,5,5,6,6,7,7]
+; ZU-NEXT:    psrad $24, %xmm1
+; ZU-NEXT:    punpckhwd {{.*#+}} xmm4 = xmm4[4,4,5,5,6,6,7,7]
+; ZU-NEXT:    psrad $24, %xmm4
+; ZU-NEXT:    movdqa %xmm4, %xmm5
+; ZU-NEXT:    pcmpgtd %xmm1, %xmm5
+; ZU-NEXT:    pcmpgtd %xmm4, %xmm1
+; ZU-NEXT:    psubd %xmm5, %xmm1
+; ZU-NEXT:    punpckhbw {{.*#+}} xmm4 = xmm4[8],xmm2[8],xmm4[9],xmm2[9],xmm4[10],xmm2[10],xmm4[11],xmm2[11],xmm4[12],xmm2[12],xmm4[13],xmm2[13],xmm4[14],xmm2[14],xmm4[15],xmm2[15]
+; ZU-NEXT:    punpcklwd {{.*#+}} xmm2 = xmm2[0],xmm4[0],xmm2[1],xmm4[1],xmm2[2],xmm4[2],xmm2[3],xmm4[3]
+; ZU-NEXT:    psrad $24, %xmm2
+; ZU-NEXT:    punpckhbw {{.*#+}} xmm5 = xmm5[8],xmm3[8],xmm5[9],xmm3[9],xmm5[10],xmm3[10],xmm5[11],xmm3[11],xmm5[12],xmm3[12],xmm5[13],xmm3[13],xmm5[14],xmm3[14],xmm5[15],xmm3[15]
+; ZU-NEXT:    punpcklwd {{.*#+}} xmm3 = xmm3[0],xmm5[0],xmm3[1],xmm5[1],xmm3[2],xmm5[2],xmm3[3],xmm5[3]
+; ZU-NEXT:    psrad $24, %xmm3
+; ZU-NEXT:    movdqa %xmm3, %xmm6
+; ZU-NEXT:    pcmpgtd %xmm2, %xmm6
+; ZU-NEXT:    pcmpgtd %xmm3, %xmm2
+; ZU-NEXT:    psubd %xmm6, %xmm2
+; ZU-NEXT:    punpckhwd {{.*#+}} xmm3 = xmm3[4],xmm4[4],xmm3[5],xmm4[5],xmm3[6],xmm4[6],xmm3[7],xmm4[7]
+; ZU-NEXT:    psrad $24, %xmm3
+; ZU-NEXT:    punpckhwd {{.*#+}} xmm4 = xmm4[4],xmm5[4],xmm4[5],xmm5[5],xmm4[6],xmm5[6],xmm4[7],xmm5[7]
+; ZU-NEXT:    psrad $24, %xmm4
+; ZU-NEXT:    movdqa %xmm4, %xmm5
+; ZU-NEXT:    pcmpgtd %xmm3, %xmm5
+; ZU-NEXT:    pcmpgtd %xmm4, %xmm3
+; ZU-NEXT:    psubd %xmm5, %xmm3
+; ZU-NEXT:    retq
   %1 = call <16 x i32> @llvm.scmp(<16 x i8> %x, <16 x i8> %y)
   ret <16 x i32> %1
 }
@@ -3941,23 +3884,14 @@ define i128 @sext_scmp_i128_zero(i128 %x) nounwind {
 ; X86-NEXT:    popl %ebp
 ; X86-NEXT:    retl $4
 ;
-; SETZUCC-LABEL: sext_scmp_i128_zero:
-; SETZUCC:       # %bb.0:
-; SETZUCC-NEXT:    movq %rsi, %rdx
-; SETZUCC-NEXT:    orq %rsi, %rdi
-; SETZUCC-NEXT:    setzune %al
-; SETZUCC-NEXT:    sarq $63, %rdx
-; SETZUCC-NEXT:    orq %rdx, %rax
-; SETZUCC-NEXT:    retq
-;
-; NO-SETZUCC-LABEL: sext_scmp_i128_zero:
-; NO-SETZUCC:       # %bb.0:
-; NO-SETZUCC-NEXT:    movq %rsi, %rdx
-; NO-SETZUCC-NEXT:    orq %rsi, %rdi
-; NO-SETZUCC-NEXT:    setzune %al
-; NO-SETZUCC-NEXT:    sarq $63, %rdx
-; NO-SETZUCC-NEXT:    orq %rdx, %rax
-; NO-SETZUCC-NEXT:    retq
+; ZU-LABEL: sext_scmp_i128_zero:
+; ZU:       # %bb.0:
+; ZU-NEXT:    movq %rsi, %rdx
+; ZU-NEXT:    orq %rsi, %rdi
+; ZU-NEXT:    setzune %al
+; ZU-NEXT:    sarq $63, %rdx
+; ZU-NEXT:    orq %rdx, %rax
+; ZU-NEXT:    retq
   %cmp = call i8 @llvm.scmp.i8.i128(i128 %x, i128 0)
   %ext = sext i8 %cmp to i128
   ret i128 %ext
@@ -3971,8 +3905,7 @@ define i64 @sext_scmp_i128_to_i64(i128 %x) nounwind {
 ; X64-NEXT:    orq %rsi, %rdi
 ; X64-NEXT:    setne %al
 ; X64-NEXT:    sarq $63, %rsi
-; X64-NEXT:    orl %eax, %esi
-; X64-NEXT:    movsbq %sil, %rax
+; X64-NEXT:    orq %rsi, %rax
 ; X64-NEXT:    retq
 ;
 ; X86-LABEL: sext_scmp_i128_to_i64:
@@ -3997,23 +3930,13 @@ define i64 @sext_scmp_i128_to_i64(i128 %x) nounwind {
 ; X86-NEXT:    popl %ebp
 ; X86-NEXT:    retl
 ;
-; SETZUCC-LABEL: sext_scmp_i128_to_i64:
-; SETZUCC:       # %bb.0:
-; SETZUCC-NEXT:    orq %rsi, %rdi
-; SETZUCC-NEXT:    setzune %al
-; SETZUCC-NEXT:    sarq $63, %rsi
-; SETZUCC-NEXT:    orl %eax, %esi
-; SETZUCC-NEXT:    movsbq %sil, %rax
-; SETZUCC-NEXT:    retq
-;
-; NO-SETZUCC-LABEL: sext_scmp_i128_to_i64:
-; NO-SETZUCC:       # %bb.0:
-; NO-SETZUCC-NEXT:    orq %rsi, %rdi
-; NO-SETZUCC-NEXT:    setzune %al
-; NO-SETZUCC-NEXT:    sarq $63, %rsi
-; NO-SETZUCC-NEXT:    orl %eax, %esi
-; NO-SETZUCC-NEXT:    movsbq %sil, %rax
-; NO-SETZUCC-NEXT:    retq
+; ZU-LABEL: sext_scmp_i128_to_i64:
+; ZU:       # %bb.0:
+; ZU-NEXT:    orq %rsi, %rdi
+; ZU-NEXT:    setzune %al
+; ZU-NEXT:    sarq $63, %rsi
+; ZU-NEXT:    orq %rsi, %rax
+; ZU-NEXT:    retq
   %cmp = call i8 @llvm.scmp.i8.i128(i128 %x, i128 0)
   %ext = sext i8 %cmp to i64
   ret i64 %ext
@@ -4054,23 +3977,14 @@ define i8 @scmp_i128_zero_to_i8(i128 %x) nounwind {
 ; X86-NEXT:    popl %ebp
 ; X86-NEXT:    retl
 ;
-; SETZUCC-LABEL: scmp_i128_zero_to_i8:
-; SETZUCC:       # %bb.0:
-; SETZUCC-NEXT:    orq %rsi, %rdi
-; SETZUCC-NEXT:    setzune %al
-; SETZUCC-NEXT:    sarq $63, %rsi
-; SETZUCC-NEXT:    orl %esi, %eax
-; SETZUCC-NEXT:    # kill: def $al killed $al killed $eax
-; SETZUCC-NEXT:    retq
-;
-; NO-SETZUCC-LABEL: scmp_i128_zero_to_i8:
-; NO-SETZUCC:       # %bb.0:
-; NO-SETZUCC-NEXT:    orq %rsi, %rdi
-; NO-SETZUCC-NEXT:    setzune %al
-; NO-SETZUCC-NEXT:    sarq $63, %rsi
-; NO-SETZUCC-NEXT:    orl %esi, %eax
-; NO-SETZUCC-NEXT:    # kill: def $al killed $al killed $eax
-; NO-SETZUCC-NEXT:    retq
+; ZU-LABEL: scmp_i128_zero_to_i8:
+; ZU:       # %bb.0:
+; ZU-NEXT:    orq %rsi, %rdi
+; ZU-NEXT:    setzune %al
+; ZU-NEXT:    sarq $63, %rsi
+; ZU-NEXT:    orl %esi, %eax
+; ZU-NEXT:    # kill: def $al killed $al killed $eax
+; ZU-NEXT:    retq
   %r = call i8 @llvm.scmp.i8.i128(i128 %x, i128 0)
   ret i8 %r
 }

>From 1f248537c4d7694d783cb0b0e7ab52acb8608660 Mon Sep 17 00:00:00 2001
From: Takashiidobe <idobetakashi at gmail.com>
Date: Wed, 8 Apr 2026 09:26:22 -0400
Subject: [PATCH 5/8] code review feedback: use getBooleanContents as a
 condition to check for setcc result type since it isn't always an i1.

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp    | 7 ++++++-
 llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 7 ++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 393fe841d1326..0c67a1ad0ad1e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -15162,13 +15162,18 @@ static SDValue tryToFoldSExtOfSCMP(SDNode *N, const SDLoc &DL,
   if (!InVT.isScalarInteger())
     return SDValue();
   SDValue X = N0.getOperand(0);
-  SDValue ShiftAmt = DAG.getConstant(InVT.getScalarSizeInBits() - 1, DL, InVT);
+  SDValue ShiftAmt =
+      DAG.getShiftAmountConstant(InVT.getScalarSizeInBits() - 1, InVT, DL);
   SDValue SignMask = DAG.getNode(ISD::SRA, DL, InVT, X, ShiftAmt);
   EVT BoolVT =
       TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), InVT);
   SDValue IsNZ =
       DAG.getSetCC(DL, BoolVT, X, DAG.getConstant(0, DL, InVT), ISD::SETNE);
   SDValue IsNZExt = DAG.getZExtOrTrunc(IsNZ, DL, InVT);
+  if (BoolVT.getScalarSizeInBits() != 1 &&
+      TLI.getBooleanContents(BoolVT) != TargetLowering::ZeroOrOneBooleanContent)
+    IsNZExt =
+        DAG.getNode(ISD::AND, DL, InVT, IsNZExt, DAG.getConstant(1, DL, InVT));
   SDValue Result = DAG.getNode(ISD::OR, DL, InVT, SignMask, IsNZExt);
   return DAG.getSExtOrTrunc(Result, DL, VT);
 }
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 9c032722537b8..9e4e1026d9ad1 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -11485,10 +11485,15 @@ SDValue TargetLowering::expandCMP(SDNode *Node, SelectionDAG &DAG) const {
   // nonzero test is a single comparison, with no flag-chain dependencies
   // between them.
   if (Opcode == ISD::SCMP && isNullConstant(RHS) && VT.isScalarInteger()) {
-    SDValue ShiftAmt = DAG.getConstant(VT.getScalarSizeInBits() - 1, dl, VT);
+    SDValue ShiftAmt =
+        DAG.getShiftAmountConstant(VT.getScalarSizeInBits() - 1, VT, dl);
     SDValue SignMask = DAG.getNode(ISD::SRA, dl, VT, LHS, ShiftAmt);
     SDValue IsNZ = DAG.getSetCC(dl, BoolVT, LHS, RHS, ISD::SETNE);
     SDValue IsNZExt = DAG.getZExtOrTrunc(IsNZ, dl, VT);
+    if (BoolVT.getScalarSizeInBits() != 1 &&
+        getBooleanContents(BoolVT) != ZeroOrOneBooleanContent)
+      IsNZExt =
+          DAG.getNode(ISD::AND, dl, VT, IsNZExt, DAG.getConstant(1, dl, VT));
     SDValue Result = DAG.getNode(ISD::OR, dl, VT, SignMask, IsNZExt);
     return DAG.getSExtOrTrunc(Result, dl, ResVT);
   }

>From dd0a6b895e30a515c43d3879ae54ff61321028ef Mon Sep 17 00:00:00 2001
From: Takashiidobe <idobetakashi at gmail.com>
Date: Wed, 8 Apr 2026 20:39:13 -0400
Subject: [PATCH 6/8] code review feedback: turn sext(scmp(X, Y)) and
 sext(ucmp(X, y)) -> scmp/ucmp(X, Y) in instcombine instead of DAGCombiner for
 better separation of concerns between folds. Also add a lot more tests for
 scmp/ucmp

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 36 ------------
 .../InstCombine/InstCombineCasts.cpp          | 14 +++++
 llvm/test/CodeGen/AArch64/scmp.ll             | 21 +++++++
 llvm/test/CodeGen/AArch64/ucmp.ll             | 21 +++++++
 llvm/test/CodeGen/ARM/scmp.ll                 | 14 +++++
 llvm/test/CodeGen/ARM/ucmp.ll                 | 14 +++++
 llvm/test/CodeGen/LoongArch/scmp.ll           | 15 +++++
 llvm/test/CodeGen/LoongArch/ucmp.ll           | 15 +++++
 llvm/test/CodeGen/PowerPC/scmp.ll             | 17 ++++++
 llvm/test/CodeGen/PowerPC/ucmp.ll             | 17 ++++++
 llvm/test/CodeGen/RISCV/scmp.ll               | 22 +++++++
 llvm/test/CodeGen/RISCV/ucmp.ll               | 22 +++++++
 llvm/test/CodeGen/SystemZ/scmp.ll             | 14 +++++
 llvm/test/CodeGen/SystemZ/ucmp.ll             | 14 +++++
 llvm/test/CodeGen/Thumb/scmp.ll               | 45 +++++++++++++++
 llvm/test/CodeGen/Thumb/ucmp.ll               | 35 ++++++++++++
 llvm/test/CodeGen/WebAssembly/scmp.ll         | 18 ++++++
 llvm/test/CodeGen/WebAssembly/ucmp.ll         | 18 ++++++
 llvm/test/CodeGen/X86/scmp.ll                 | 57 +++++++++++++++++--
 llvm/test/CodeGen/X86/ucmp.ll                 | 23 ++++++++
 llvm/test/Transforms/InstCombine/scmp.ll      | 28 +++++++++
 llvm/test/Transforms/InstCombine/ucmp.ll      | 12 ++++
 22 files changed, 451 insertions(+), 41 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 0c67a1ad0ad1e..383e45c5ea3a8 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -15145,39 +15145,6 @@ SDValue DAGCombiner::foldSextSetcc(SDNode *N) {
   return SDValue();
 }
 
-// fold sext(scmp(x, 0)) -> or(sra(x, bw-1)), zext(setne(x, 0))
-// Valid for any sext result width: -1/0/1 in the input type truncates or
-// sign-extends correctly to any wider or narrower integer type.
-// This avoids the generic sub(IsGT,IsLT) expansion and the narrow round-trip
-// through the scmp result type, producing a sign-mask OR nonzero-flag
-// sequence in the input type instead.
-static SDValue tryToFoldSExtOfSCMP(SDNode *N, const SDLoc &DL,
-                                   const TargetLowering &TLI,
-                                   SelectionDAG &DAG) {
-  SDValue N0 = N->getOperand(0);
-  EVT VT = N->getValueType(0);
-  if (N0.getOpcode() != ISD::SCMP || !isNullConstant(N0.getOperand(1)))
-    return SDValue();
-  EVT InVT = N0.getOperand(0).getValueType();
-  if (!InVT.isScalarInteger())
-    return SDValue();
-  SDValue X = N0.getOperand(0);
-  SDValue ShiftAmt =
-      DAG.getShiftAmountConstant(InVT.getScalarSizeInBits() - 1, InVT, DL);
-  SDValue SignMask = DAG.getNode(ISD::SRA, DL, InVT, X, ShiftAmt);
-  EVT BoolVT =
-      TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), InVT);
-  SDValue IsNZ =
-      DAG.getSetCC(DL, BoolVT, X, DAG.getConstant(0, DL, InVT), ISD::SETNE);
-  SDValue IsNZExt = DAG.getZExtOrTrunc(IsNZ, DL, InVT);
-  if (BoolVT.getScalarSizeInBits() != 1 &&
-      TLI.getBooleanContents(BoolVT) != TargetLowering::ZeroOrOneBooleanContent)
-    IsNZExt =
-        DAG.getNode(ISD::AND, DL, InVT, IsNZExt, DAG.getConstant(1, DL, InVT));
-  SDValue Result = DAG.getNode(ISD::OR, DL, InVT, SignMask, IsNZExt);
-  return DAG.getSExtOrTrunc(Result, DL, VT);
-}
-
 SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
   SDValue N0 = N->getOperand(0);
   EVT VT = N->getValueType(0);
@@ -15194,9 +15161,6 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) {
   if (SDValue Res = tryToFoldExtendOfConstant(N, DL, TLI, DAG, LegalTypes))
     return Res;
 
-  if (SDValue Res = tryToFoldSExtOfSCMP(N, DL, TLI, DAG))
-    return Res;
-
   // fold (sext (sext x)) -> (sext x)
   // fold (sext (aext x)) -> (sext x)
   if (N0.getOpcode() == ISD::SIGN_EXTEND || N0.getOpcode() == ISD::ANY_EXTEND)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index a1d67a0c60ac5..7d3fe11e58228 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -21,6 +21,8 @@
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/Instruction.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/PatternMatch.h"
 #include "llvm/IR/Type.h"
 #include "llvm/IR/Value.h"
@@ -1922,6 +1924,18 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) {
     }
   }
 
+  // sext(scmp(x, y)) -> scmp(x, y) with a wider result type.
+  // sext(ucmp(x, y)) -> ucmp(x, y) with a wider result type.
+  // scmp/ucmp return only -1, 0, or 1, which sign-extend correctly to any
+  // wider integer type, so we can sink the extension into the intrinsic.
+  if (auto *II = dyn_cast<IntrinsicInst>(Src)) {
+    Intrinsic::ID IID = II->getIntrinsicID();
+    if ((IID == Intrinsic::scmp || IID == Intrinsic::ucmp) && II->hasOneUse())
+      return replaceInstUsesWith(
+          Sext, Builder.CreateIntrinsic(
+                    DestTy, IID, {II->getArgOperand(0), II->getArgOperand(1)}));
+  }
+
   return nullptr;
 }
 
diff --git a/llvm/test/CodeGen/AArch64/scmp.ll b/llvm/test/CodeGen/AArch64/scmp.ll
index 73cbd2cbeee48..3acabaaaace44 100644
--- a/llvm/test/CodeGen/AArch64/scmp.ll
+++ b/llvm/test/CodeGen/AArch64/scmp.ll
@@ -318,3 +318,24 @@ entry:
   %or.i = tail call <16 x i8> @llvm.scmp.v16i8.v16i16(<16 x i16> %0, <16 x i16> %1)
   ret <16 x i8> %or.i
 }
+
+; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
+define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
+; CHECK-SD-LABEL: sext_scmp_i32:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    cmp w0, w1
+; CHECK-SD-NEXT:    cset w8, gt
+; CHECK-SD-NEXT:    csinv w8, w8, wzr, ge
+; CHECK-SD-NEXT:    sxtb w0, w8
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: sext_scmp_i32:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    cmp w0, w1
+; CHECK-GI-NEXT:    cset w8, gt
+; CHECK-GI-NEXT:    csinv w0, w8, wzr, ge
+; CHECK-GI-NEXT:    ret
+  %cmp = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/AArch64/ucmp.ll b/llvm/test/CodeGen/AArch64/ucmp.ll
index af8225307fedd..9f8c2670536fa 100644
--- a/llvm/test/CodeGen/AArch64/ucmp.ll
+++ b/llvm/test/CodeGen/AArch64/ucmp.ll
@@ -356,3 +356,24 @@ entry:
   %or.i = tail call <16 x i8> @llvm.ucmp.v16i8.v16i16(<16 x i16> %0, <16 x i16> %1)
   ret <16 x i8> %or.i
 }
+
+; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
+define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
+; CHECK-SD-LABEL: sext_ucmp_i32:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    cmp w0, w1
+; CHECK-SD-NEXT:    cset w8, hi
+; CHECK-SD-NEXT:    csinv w8, w8, wzr, hs
+; CHECK-SD-NEXT:    sxtb w0, w8
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: sext_ucmp_i32:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    cmp w0, w1
+; CHECK-GI-NEXT:    cset w8, hi
+; CHECK-GI-NEXT:    csinv w0, w8, wzr, hs
+; CHECK-GI-NEXT:    ret
+  %cmp = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/ARM/scmp.ll b/llvm/test/CodeGen/ARM/scmp.ll
index 9189aee6aaf43..b9892fbced8fc 100644
--- a/llvm/test/CodeGen/ARM/scmp.ll
+++ b/llvm/test/CodeGen/ARM/scmp.ll
@@ -141,3 +141,17 @@ define i64 @scmp_64_64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.scmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
+define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: sext_scmp_i32:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    subs r0, r0, r1
+; CHECK-NEXT:    movwgt r0, #1
+; CHECK-NEXT:    mvnlt r0, #0
+; CHECK-NEXT:    sxtb r0, r0
+; CHECK-NEXT:    bx lr
+  %cmp = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/ARM/ucmp.ll b/llvm/test/CodeGen/ARM/ucmp.ll
index bb0201454d1ea..ed3b1a579947b 100644
--- a/llvm/test/CodeGen/ARM/ucmp.ll
+++ b/llvm/test/CodeGen/ARM/ucmp.ll
@@ -129,3 +129,17 @@ define i64 @ucmp_64_64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.ucmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
+define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: sext_ucmp_i32:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    subs r0, r0, r1
+; CHECK-NEXT:    movwhi r0, #1
+; CHECK-NEXT:    mvnlo r0, #0
+; CHECK-NEXT:    sxtb r0, r0
+; CHECK-NEXT:    bx lr
+  %cmp = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/LoongArch/scmp.ll b/llvm/test/CodeGen/LoongArch/scmp.ll
index 69a92968173d2..3c5f7aa27756c 100644
--- a/llvm/test/CodeGen/LoongArch/scmp.ll
+++ b/llvm/test/CodeGen/LoongArch/scmp.ll
@@ -102,3 +102,18 @@ define i64 @scmp.64.64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.scmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
+define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: sext_scmp_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    addi.w $a1, $a1, 0
+; CHECK-NEXT:    addi.w $a0, $a0, 0
+; CHECK-NEXT:    slt $a2, $a0, $a1
+; CHECK-NEXT:    slt $a0, $a1, $a0
+; CHECK-NEXT:    sub.d $a0, $a0, $a2
+; CHECK-NEXT:    ret
+  %cmp = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/LoongArch/ucmp.ll b/llvm/test/CodeGen/LoongArch/ucmp.ll
index b91d3bf15d812..b952cd51c798f 100644
--- a/llvm/test/CodeGen/LoongArch/ucmp.ll
+++ b/llvm/test/CodeGen/LoongArch/ucmp.ll
@@ -102,3 +102,18 @@ define i64 @ucmp.64.64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.ucmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
+define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: sext_ucmp_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    addi.w $a1, $a1, 0
+; CHECK-NEXT:    addi.w $a0, $a0, 0
+; CHECK-NEXT:    sltu $a2, $a0, $a1
+; CHECK-NEXT:    sltu $a0, $a1, $a0
+; CHECK-NEXT:    sub.d $a0, $a0, $a2
+; CHECK-NEXT:    ret
+  %cmp = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/PowerPC/scmp.ll b/llvm/test/CodeGen/PowerPC/scmp.ll
index 107137c0bea7c..1e7f7e7691fed 100644
--- a/llvm/test/CodeGen/PowerPC/scmp.ll
+++ b/llvm/test/CodeGen/PowerPC/scmp.ll
@@ -125,3 +125,20 @@ define i64 @scmp_64_64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.scmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
+define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: sext_scmp_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    extsw 4, 4
+; CHECK-NEXT:    extsw 3, 3
+; CHECK-NEXT:    cmpw 3, 4
+; 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
+  %cmp = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/PowerPC/ucmp.ll b/llvm/test/CodeGen/PowerPC/ucmp.ll
index 6ece83c35e1fc..cacfebc4bfba8 100644
--- a/llvm/test/CodeGen/PowerPC/ucmp.ll
+++ b/llvm/test/CodeGen/PowerPC/ucmp.ll
@@ -112,3 +112,20 @@ define i64 @ucmp_64_64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.ucmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
+define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: sext_ucmp_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    clrldi 3, 3, 32
+; CHECK-NEXT:    clrldi 4, 4, 32
+; CHECK-NEXT:    sub 5, 3, 4
+; CHECK-NEXT:    subc 6, 4, 3
+; CHECK-NEXT:    subfe 3, 4, 3
+; CHECK-NEXT:    subfe 3, 3, 5
+; CHECK-NEXT:    extsb 3, 3
+; CHECK-NEXT:    blr
+  %cmp = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/RISCV/scmp.ll b/llvm/test/CodeGen/RISCV/scmp.ll
index 56c876a2409d2..df572c75819b8 100644
--- a/llvm/test/CodeGen/RISCV/scmp.ll
+++ b/llvm/test/CodeGen/RISCV/scmp.ll
@@ -222,3 +222,25 @@ define i64 @scmp.64.64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.scmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
+define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
+; RV32I-LABEL: sext_scmp_i32:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    slt a2, a0, a1
+; RV32I-NEXT:    slt a0, a1, a0
+; RV32I-NEXT:    sub a0, a0, a2
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: sext_scmp_i32:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    sext.w a1, a1
+; RV64I-NEXT:    sext.w a0, a0
+; RV64I-NEXT:    slt a2, a0, a1
+; RV64I-NEXT:    slt a0, a1, a0
+; RV64I-NEXT:    sub a0, a0, a2
+; RV64I-NEXT:    ret
+  %cmp = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/RISCV/ucmp.ll b/llvm/test/CodeGen/RISCV/ucmp.ll
index 0a400b1c04a3f..5e666d852bab3 100644
--- a/llvm/test/CodeGen/RISCV/ucmp.ll
+++ b/llvm/test/CodeGen/RISCV/ucmp.ll
@@ -258,3 +258,25 @@ define i64 @ucmp.64.64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.ucmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
+define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
+; RV32I-LABEL: sext_ucmp_i32:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    sltu a2, a0, a1
+; RV32I-NEXT:    sltu a0, a1, a0
+; RV32I-NEXT:    sub a0, a0, a2
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: sext_ucmp_i32:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    sext.w a1, a1
+; RV64I-NEXT:    sext.w a0, a0
+; RV64I-NEXT:    sltu a2, a0, a1
+; RV64I-NEXT:    sltu a0, a1, a0
+; RV64I-NEXT:    sub a0, a0, a2
+; RV64I-NEXT:    ret
+  %cmp = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/SystemZ/scmp.ll b/llvm/test/CodeGen/SystemZ/scmp.ll
index 3ecaa60a58d24..6caa2d9276777 100644
--- a/llvm/test/CodeGen/SystemZ/scmp.ll
+++ b/llvm/test/CodeGen/SystemZ/scmp.ll
@@ -107,3 +107,17 @@ define i64 @scmp.64.64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.scmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
+define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: sext_scmp_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cr %r2, %r3
+; CHECK-NEXT:    lhi %r2, 0
+; CHECK-NEXT:    lochih %r2, 1
+; CHECK-NEXT:    lochil %r2, -1
+; CHECK-NEXT:    br %r14
+  %cmp = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/SystemZ/ucmp.ll b/llvm/test/CodeGen/SystemZ/ucmp.ll
index 4175cd7850a98..8906c34158539 100644
--- a/llvm/test/CodeGen/SystemZ/ucmp.ll
+++ b/llvm/test/CodeGen/SystemZ/ucmp.ll
@@ -107,3 +107,17 @@ define i64 @ucmp.64.64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.ucmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
+define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: sext_ucmp_i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    clr %r2, %r3
+; CHECK-NEXT:    lhi %r2, 0
+; CHECK-NEXT:    lochih %r2, 1
+; CHECK-NEXT:    lochil %r2, -1
+; CHECK-NEXT:    br %r14
+  %cmp = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/Thumb/scmp.ll b/llvm/test/CodeGen/Thumb/scmp.ll
index c0024492b3a6d..b9584e4168a6e 100644
--- a/llvm/test/CodeGen/Thumb/scmp.ll
+++ b/llvm/test/CodeGen/Thumb/scmp.ll
@@ -418,3 +418,48 @@ define i64 @scmp_64_64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.scmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
+define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
+; THUMB1-LABEL: sext_scmp_i32:
+; THUMB1:       @ %bb.0:
+; THUMB1-NEXT:    movs r2, #1
+; THUMB1-NEXT:    movs r3, #0
+; THUMB1-NEXT:    cmp r0, r1
+; THUMB1-NEXT:    mov r0, r2
+; THUMB1-NEXT:    bge .LBB8_3
+; THUMB1-NEXT:  @ %bb.1:
+; THUMB1-NEXT:    ble .LBB8_4
+; THUMB1-NEXT:  .LBB8_2:
+; THUMB1-NEXT:    subs r0, r2, r0
+; THUMB1-NEXT:    bx lr
+; THUMB1-NEXT:  .LBB8_3:
+; THUMB1-NEXT:    mov r0, r3
+; THUMB1-NEXT:    bgt .LBB8_2
+; THUMB1-NEXT:  .LBB8_4:
+; THUMB1-NEXT:    mov r2, r3
+; THUMB1-NEXT:    subs r0, r2, r0
+; THUMB1-NEXT:    bx lr
+;
+; THUMB2-LABEL: sext_scmp_i32:
+; THUMB2:       @ %bb.0:
+; THUMB2-NEXT:    subs r0, r0, r1
+; THUMB2-NEXT:    it gt
+; THUMB2-NEXT:    movgt r0, #1
+; THUMB2-NEXT:    it lt
+; THUMB2-NEXT:    movlt.w r0, #-1
+; THUMB2-NEXT:    sxtb r0, r0
+; THUMB2-NEXT:    bx lr
+;
+; V81M-LABEL: sext_scmp_i32:
+; V81M:       @ %bb.0:
+; V81M-NEXT:    cmp r0, r1
+; V81M-NEXT:    cset r0, gt
+; V81M-NEXT:    it lt
+; V81M-NEXT:    movlt.w r0, #-1
+; V81M-NEXT:    sxtb r0, r0
+; V81M-NEXT:    bx lr
+  %cmp = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/Thumb/ucmp.ll b/llvm/test/CodeGen/Thumb/ucmp.ll
index 5d0f57e2a9d72..8f09e581604f2 100644
--- a/llvm/test/CodeGen/Thumb/ucmp.ll
+++ b/llvm/test/CodeGen/Thumb/ucmp.ll
@@ -374,3 +374,38 @@ define i64 @ucmp_64_64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.ucmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
+define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
+; THUMB1-LABEL: sext_ucmp_i32:
+; THUMB1:       @ %bb.0:
+; THUMB1-NEXT:    subs r2, r0, r1
+; THUMB1-NEXT:    sbcs r2, r2
+; THUMB1-NEXT:    cmp r1, r0
+; THUMB1-NEXT:    sbcs r1, r1
+; THUMB1-NEXT:    subs r0, r2, r1
+; THUMB1-NEXT:    sxtb r0, r0
+; THUMB1-NEXT:    bx lr
+;
+; THUMB2-LABEL: sext_ucmp_i32:
+; THUMB2:       @ %bb.0:
+; THUMB2-NEXT:    subs r0, r0, r1
+; THUMB2-NEXT:    it hi
+; THUMB2-NEXT:    movhi r0, #1
+; THUMB2-NEXT:    it lo
+; THUMB2-NEXT:    movlo.w r0, #-1
+; THUMB2-NEXT:    sxtb r0, r0
+; THUMB2-NEXT:    bx lr
+;
+; V81M-LABEL: sext_ucmp_i32:
+; V81M:       @ %bb.0:
+; V81M-NEXT:    cmp r0, r1
+; V81M-NEXT:    cset r0, hi
+; V81M-NEXT:    it lo
+; V81M-NEXT:    movlo.w r0, #-1
+; V81M-NEXT:    sxtb r0, r0
+; V81M-NEXT:    bx lr
+  %cmp = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/WebAssembly/scmp.ll b/llvm/test/CodeGen/WebAssembly/scmp.ll
index 60ab6ef2f527a..c02e47dac265f 100644
--- a/llvm/test/CodeGen/WebAssembly/scmp.ll
+++ b/llvm/test/CodeGen/WebAssembly/scmp.ll
@@ -145,3 +145,21 @@ define i64 @scmp.64.64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.scmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
+define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: sext_scmp_i32:
+; CHECK:         .functype sext_scmp_i32 (i32, i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get $push4=, 0
+; CHECK-NEXT:    local.get $push3=, 1
+; CHECK-NEXT:    i32.gt_s $push1=, $pop4, $pop3
+; CHECK-NEXT:    local.get $push6=, 0
+; CHECK-NEXT:    local.get $push5=, 1
+; CHECK-NEXT:    i32.lt_s $push0=, $pop6, $pop5
+; CHECK-NEXT:    i32.sub $push2=, $pop1, $pop0
+; CHECK-NEXT:    # fallthrough-return
+  %cmp = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/WebAssembly/ucmp.ll b/llvm/test/CodeGen/WebAssembly/ucmp.ll
index ab7f9b2bab1da..6f6456d9f9df5 100644
--- a/llvm/test/CodeGen/WebAssembly/ucmp.ll
+++ b/llvm/test/CodeGen/WebAssembly/ucmp.ll
@@ -145,3 +145,21 @@ define i64 @ucmp.64.64(i64 %x, i64 %y) nounwind {
   %1 = call i64 @llvm.ucmp(i64 %x, i64 %y)
   ret i64 %1
 }
+
+; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
+define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
+; CHECK-LABEL: sext_ucmp_i32:
+; CHECK:         .functype sext_ucmp_i32 (i32, i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get $push4=, 0
+; CHECK-NEXT:    local.get $push3=, 1
+; CHECK-NEXT:    i32.gt_u $push1=, $pop4, $pop3
+; CHECK-NEXT:    local.get $push6=, 0
+; CHECK-NEXT:    local.get $push5=, 1
+; CHECK-NEXT:    i32.lt_u $push0=, $pop6, $pop5
+; CHECK-NEXT:    i32.sub $push2=, $pop1, $pop0
+; CHECK-NEXT:    # fallthrough-return
+  %cmp = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/X86/scmp.ll b/llvm/test/CodeGen/X86/scmp.ll
index 17ec6a7858795..475b31e2c2f80 100644
--- a/llvm/test/CodeGen/X86/scmp.ll
+++ b/llvm/test/CodeGen/X86/scmp.ll
@@ -3843,8 +3843,8 @@ define <2 x i16> @scmp_ret_wider_than_operands(<2 x i8> %x, <2 x i8> %y) nounwin
 }
 
 
-; sext(scmp(x, 0)) where result type == input type folds to
-; or(sra(x, bw-1), zext(setne(x, 0))), avoiding the i8 round-trip.
+; InstCombine folds sext(scmp(x, 0)) -> scmp(x, 0) with a wider result type,
+; then expandCMP lowers the wider scmp to or(sra(x, bw-1), zext(setne(x, 0))).
 define i128 @sext_scmp_i128_zero(i128 %x) nounwind {
 ; X64-LABEL: sext_scmp_i128_zero:
 ; X64:       # %bb.0:
@@ -3897,7 +3897,9 @@ define i128 @sext_scmp_i128_zero(i128 %x) nounwind {
   ret i128 %ext
 }
 
-; sext to a narrower width also folds: compute in input type, truncate down.
+; InstCombine folds sext(scmp(x, 0)) -> scmp(x, 0) with i64 result type,
+; then expandCMP lowers the wider scmp to or(sra(x, bw-1), zext(setne(x, 0)))
+; truncated to i64.
 define i64 @sext_scmp_i128_to_i64(i128 %x) nounwind {
 ; X64-LABEL: sext_scmp_i128_to_i64:
 ; X64:       # %bb.0:
@@ -3905,7 +3907,8 @@ define i64 @sext_scmp_i128_to_i64(i128 %x) nounwind {
 ; X64-NEXT:    orq %rsi, %rdi
 ; X64-NEXT:    setne %al
 ; X64-NEXT:    sarq $63, %rsi
-; X64-NEXT:    orq %rsi, %rax
+; X64-NEXT:    orl %eax, %esi
+; X64-NEXT:    movsbq %sil, %rax
 ; X64-NEXT:    retq
 ;
 ; X86-LABEL: sext_scmp_i128_to_i64:
@@ -3935,7 +3938,8 @@ define i64 @sext_scmp_i128_to_i64(i128 %x) nounwind {
 ; ZU-NEXT:    orq %rsi, %rdi
 ; ZU-NEXT:    setzune %al
 ; ZU-NEXT:    sarq $63, %rsi
-; ZU-NEXT:    orq %rsi, %rax
+; ZU-NEXT:    orl %eax, %esi
+; ZU-NEXT:    movsbq %sil, %rax
 ; ZU-NEXT:    retq
   %cmp = call i8 @llvm.scmp.i8.i128(i128 %x, i128 0)
   %ext = sext i8 %cmp to i64
@@ -3988,3 +3992,46 @@ define i8 @scmp_i128_zero_to_i8(i128 %x) nounwind {
   %r = call i8 @llvm.scmp.i8.i128(i128 %x, i128 0)
   ret i8 %r
 }
+
+; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
+define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
+; X64-LABEL: sext_scmp_i32:
+; X64:       # %bb.0:
+; X64-NEXT:    cmpl %esi, %edi
+; X64-NEXT:    setl %al
+; X64-NEXT:    setg %cl
+; X64-NEXT:    subb %al, %cl
+; X64-NEXT:    movsbl %cl, %eax
+; X64-NEXT:    retq
+;
+; X86-LABEL: sext_scmp_i32:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    cmpl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    setl %al
+; X86-NEXT:    setg %cl
+; X86-NEXT:    subb %al, %cl
+; X86-NEXT:    movsbl %cl, %eax
+; X86-NEXT:    retl
+;
+; SETZUCC-LABEL: sext_scmp_i32:
+; SETZUCC:       # %bb.0:
+; SETZUCC-NEXT:    cmpl %esi, %edi
+; SETZUCC-NEXT:    setzul %al
+; SETZUCC-NEXT:    setzug %cl
+; SETZUCC-NEXT:    subb %al, %cl
+; SETZUCC-NEXT:    movsbl %cl, %eax
+; SETZUCC-NEXT:    retq
+;
+; NO-SETZUCC-LABEL: sext_scmp_i32:
+; NO-SETZUCC:       # %bb.0:
+; NO-SETZUCC-NEXT:    cmpl %esi, %edi
+; NO-SETZUCC-NEXT:    setl %al
+; NO-SETZUCC-NEXT:    setg %cl
+; NO-SETZUCC-NEXT:    subb %al, %cl
+; NO-SETZUCC-NEXT:    movsbl %cl, %eax
+; NO-SETZUCC-NEXT:    retq
+  %cmp = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/CodeGen/X86/ucmp.ll b/llvm/test/CodeGen/X86/ucmp.ll
index e4a21fcebcbe2..c6ffbd14fd4b6 100644
--- a/llvm/test/CodeGen/X86/ucmp.ll
+++ b/llvm/test/CodeGen/X86/ucmp.ll
@@ -3391,3 +3391,26 @@ define <17 x i2> @ucmp_uncommon_vectors(<17 x i71> %x, <17 x i71> %y) nounwind {
   %1 = call <17 x i2> @llvm.ucmp(<17 x i71> %x, <17 x i71> %y)
   ret <17 x i2> %1
 }
+
+; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
+define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
+; X64-LABEL: sext_ucmp_i32:
+; X64:       # %bb.0:
+; X64-NEXT:    cmpl %esi, %edi
+; X64-NEXT:    seta %al
+; X64-NEXT:    sbbb $0, %al
+; X64-NEXT:    movsbl %al, %eax
+; X64-NEXT:    retq
+;
+; X86-LABEL: sext_ucmp_i32:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    cmpl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    seta %al
+; X86-NEXT:    sbbb $0, %al
+; X86-NEXT:    movsbl %al, %eax
+; X86-NEXT:    retl
+  %cmp = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i32
+  ret i32 %ext
+}
diff --git a/llvm/test/Transforms/InstCombine/scmp.ll b/llvm/test/Transforms/InstCombine/scmp.ll
index 2ae062cdc7033..2a5cb151aa008 100644
--- a/llvm/test/Transforms/InstCombine/scmp.ll
+++ b/llvm/test/Transforms/InstCombine/scmp.ll
@@ -797,3 +797,31 @@ define i8 @scmp_ashr_slt_pattern_neg(i8 %a) {
   %retval = select i1 %cmp, i8 %a.lobit, i8 1
   ret i8 %retval
 }
+
+; sext(scmp(x, y)) folds to a scmp with a wider result type.
+define i64 @sext_scmp(i32 %x, i32 %y) {
+; CHECK-LABEL: define i64 @sext_scmp(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.scmp.i64.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %cmp = call i8 @llvm.scmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i64
+  ret i64 %ext
+}
+
+; Don't fold when scmp has multiple uses: would leave the narrow scmp alive
+; and add a second wider scmp.
+define i64 @sext_scmp_multiuse(i32 %x, i32 %y) {
+; CHECK-LABEL: define i64 @sext_scmp_multiuse(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    call void @use(i8 [[CMP]])
+; CHECK-NEXT:    [[EXT:%.*]] = sext i8 [[CMP]] to i64
+; CHECK-NEXT:    ret i64 [[EXT]]
+;
+  %cmp = call i8 @llvm.scmp(i32 %x, i32 %y)
+  call void @use(i8 %cmp)
+  %ext = sext i8 %cmp to i64
+  ret i64 %ext
+}
diff --git a/llvm/test/Transforms/InstCombine/ucmp.ll b/llvm/test/Transforms/InstCombine/ucmp.ll
index 2d5036019740c..3ccece2adf4d5 100644
--- a/llvm/test/Transforms/InstCombine/ucmp.ll
+++ b/llvm/test/Transforms/InstCombine/ucmp.ll
@@ -555,3 +555,15 @@ define i8 @scmp_from_select_eq_and_gt(i32 %x, i32 %y) {
   %r = select i1 %eq, i8 0, i8 %sel1
   ret i8 %r
 }
+
+; sext(ucmp(x, y)) folds to a ucmp with a wider result type.
+define i64 @sext_ucmp(i32 %x, i32 %y) {
+; CHECK-LABEL: define i64 @sext_ucmp(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.ucmp.i64.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    ret i64 [[TMP1]]
+;
+  %cmp = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  %ext = sext i8 %cmp to i64
+  ret i64 %ext
+}

>From 00291fb5f055a749eaf8fa2410fd1d9ce6b94332 Mon Sep 17 00:00:00 2001
From: Takashiidobe <idobetakashi at gmail.com>
Date: Wed, 8 Apr 2026 20:42:17 -0400
Subject: [PATCH 7/8] add negative instcombine ucmp test as well

---
 llvm/test/Transforms/InstCombine/ucmp.ll | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/ucmp.ll b/llvm/test/Transforms/InstCombine/ucmp.ll
index 3ccece2adf4d5..bc912d7850e83 100644
--- a/llvm/test/Transforms/InstCombine/ucmp.ll
+++ b/llvm/test/Transforms/InstCombine/ucmp.ll
@@ -567,3 +567,19 @@ define i64 @sext_ucmp(i32 %x, i32 %y) {
   %ext = sext i8 %cmp to i64
   ret i64 %ext
 }
+
+; Don't fold when ucmp has multiple uses: would leave the narrow ucmp alive
+; and add a second wider ucmp.
+define i64 @sext_ucmp_multiuse(i32 %x, i32 %y) {
+; CHECK-LABEL: define i64 @sext_ucmp_multiuse(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    call void @use(i8 [[CMP]])
+; CHECK-NEXT:    [[EXT:%.*]] = sext i8 [[CMP]] to i64
+; CHECK-NEXT:    ret i64 [[EXT]]
+;
+  %cmp = call i8 @llvm.ucmp(i32 %x, i32 %y)
+  call void @use(i8 %cmp)
+  %ext = sext i8 %cmp to i64
+  ret i64 %ext
+}

>From c52793c54b7d283a0975d9b0209583be458b2410 Mon Sep 17 00:00:00 2001
From: Takashiidobe <idobetakashi at gmail.com>
Date: Wed, 8 Apr 2026 21:02:19 -0400
Subject: [PATCH 8/8] add a similar fold to fold ucmp(x, 0) -> zext(setne(x,
 0)) as well

---
 .../CodeGen/SelectionDAG/TargetLowering.cpp   |  14 +++
 llvm/test/CodeGen/AArch64/scmp.ll             |   1 -
 llvm/test/CodeGen/AArch64/ucmp.ll             |  39 +++++-
 llvm/test/CodeGen/ARM/scmp.ll                 |   1 -
 llvm/test/CodeGen/ARM/ucmp.ll                 |  23 +++-
 llvm/test/CodeGen/LoongArch/scmp.ll           |   1 -
 llvm/test/CodeGen/LoongArch/ucmp.ll           |  20 +++-
 llvm/test/CodeGen/PowerPC/scmp.ll             |   1 -
 llvm/test/CodeGen/PowerPC/ucmp.ll             |  24 +++-
 llvm/test/CodeGen/RISCV/scmp.ll               |   1 -
 llvm/test/CodeGen/RISCV/ucmp.ll               |  38 +++++-
 llvm/test/CodeGen/SystemZ/scmp.ll             |   1 -
 llvm/test/CodeGen/SystemZ/ucmp.ll             |  25 +++-
 llvm/test/CodeGen/Thumb/scmp.ll               |   1 -
 llvm/test/CodeGen/Thumb/ucmp.ll               |  55 ++++++++-
 llvm/test/CodeGen/WebAssembly/scmp.ll         |   1 -
 llvm/test/CodeGen/WebAssembly/ucmp.ll         |  27 ++++-
 llvm/test/CodeGen/X86/scmp.ll                 |   7 --
 llvm/test/CodeGen/X86/ucmp.ll                 | 111 +++++++++++++++++-
 llvm/test/Transforms/InstCombine/scmp.ll      |   1 -
 llvm/test/Transforms/InstCombine/ucmp.ll      |   1 -
 21 files changed, 367 insertions(+), 26 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 9e4e1026d9ad1..ebda7b65306f0 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -11498,6 +11498,20 @@ SDValue TargetLowering::expandCMP(SDNode *Node, SelectionDAG &DAG) const {
     return DAG.getSExtOrTrunc(Result, dl, ResVT);
   }
 
+  // fold ucmp(x, 0) -> zext(setne(x, 0))
+  // Since 0 is the minimum unsigned value, ucmp(x, 0) is never -1,
+  // returning 0 when x == 0 and 1 otherwise. This avoids the generic
+  // sub(IsGT, IsLT) expansion and its flag-chain dependencies.
+  if (Opcode == ISD::UCMP && isNullConstant(RHS) && VT.isScalarInteger()) {
+    SDValue IsNZ = DAG.getSetCC(dl, BoolVT, LHS, RHS, ISD::SETNE);
+    SDValue IsNZExt = DAG.getZExtOrTrunc(IsNZ, dl, VT);
+    if (BoolVT.getScalarSizeInBits() != 1 &&
+        getBooleanContents(BoolVT) != ZeroOrOneBooleanContent)
+      IsNZExt =
+          DAG.getNode(ISD::AND, dl, VT, IsNZExt, DAG.getConstant(1, dl, VT));
+    return DAG.getSExtOrTrunc(IsNZExt, dl, ResVT);
+  }
+
   auto LTPredicate = (Opcode == ISD::UCMP ? ISD::SETULT : ISD::SETLT);
   auto GTPredicate = (Opcode == ISD::UCMP ? ISD::SETUGT : ISD::SETGT);
   SDValue IsLT = DAG.getSetCC(dl, BoolVT, LHS, RHS, LTPredicate);
diff --git a/llvm/test/CodeGen/AArch64/scmp.ll b/llvm/test/CodeGen/AArch64/scmp.ll
index 3acabaaaace44..099049e8b4be8 100644
--- a/llvm/test/CodeGen/AArch64/scmp.ll
+++ b/llvm/test/CodeGen/AArch64/scmp.ll
@@ -319,7 +319,6 @@ entry:
   ret <16 x i8> %or.i
 }
 
-; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
 define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
 ; CHECK-SD-LABEL: sext_scmp_i32:
 ; CHECK-SD:       // %bb.0:
diff --git a/llvm/test/CodeGen/AArch64/ucmp.ll b/llvm/test/CodeGen/AArch64/ucmp.ll
index 9f8c2670536fa..bab09ff6e8046 100644
--- a/llvm/test/CodeGen/AArch64/ucmp.ll
+++ b/llvm/test/CodeGen/AArch64/ucmp.ll
@@ -357,7 +357,6 @@ entry:
   ret <16 x i8> %or.i
 }
 
-; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
 define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
 ; CHECK-SD-LABEL: sext_ucmp_i32:
 ; CHECK-SD:       // %bb.0:
@@ -377,3 +376,41 @@ define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
   %ext = sext i8 %cmp to i32
   ret i32 %ext
 }
+
+define i8 @ucmp_i64_zero(i64 %x) nounwind {
+; CHECK-SD-LABEL: ucmp_i64_zero:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    cmp x0, #0
+; CHECK-SD-NEXT:    cset w0, ne
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: ucmp_i64_zero:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    cmp x0, #0
+; CHECK-GI-NEXT:    cset w0, hi
+; CHECK-GI-NEXT:    ret
+  %r = call i8 @llvm.ucmp.i8.i64(i64 %x, i64 0)
+  ret i8 %r
+}
+
+define i8 @ucmp_i128_zero_to_i8(i128 %x) nounwind {
+; CHECK-SD-LABEL: ucmp_i128_zero_to_i8:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    orr x8, x0, x1
+; CHECK-SD-NEXT:    cmp x8, #0
+; CHECK-SD-NEXT:    cset w0, ne
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: ucmp_i128_zero_to_i8:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    cmp x0, #0
+; CHECK-GI-NEXT:    cset w8, hi
+; CHECK-GI-NEXT:    cmp x1, #0
+; CHECK-GI-NEXT:    cset w9, hi
+; CHECK-GI-NEXT:    csel w8, w8, w9, eq
+; CHECK-GI-NEXT:    tst w8, #0x1
+; CHECK-GI-NEXT:    cset w0, ne
+; CHECK-GI-NEXT:    ret
+  %r = call i8 @llvm.ucmp.i8.i128(i128 %x, i128 0)
+  ret i8 %r
+}
diff --git a/llvm/test/CodeGen/ARM/scmp.ll b/llvm/test/CodeGen/ARM/scmp.ll
index b9892fbced8fc..fd43ccec7d881 100644
--- a/llvm/test/CodeGen/ARM/scmp.ll
+++ b/llvm/test/CodeGen/ARM/scmp.ll
@@ -142,7 +142,6 @@ define i64 @scmp_64_64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
 define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: sext_scmp_i32:
 ; CHECK:       @ %bb.0:
diff --git a/llvm/test/CodeGen/ARM/ucmp.ll b/llvm/test/CodeGen/ARM/ucmp.ll
index ed3b1a579947b..3c37296a8095e 100644
--- a/llvm/test/CodeGen/ARM/ucmp.ll
+++ b/llvm/test/CodeGen/ARM/ucmp.ll
@@ -130,7 +130,6 @@ define i64 @ucmp_64_64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
 define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: sext_ucmp_i32:
 ; CHECK:       @ %bb.0:
@@ -143,3 +142,25 @@ define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
   %ext = sext i8 %cmp to i32
   ret i32 %ext
 }
+
+define i8 @ucmp_i64_zero(i64 %x) nounwind {
+; CHECK-LABEL: ucmp_i64_zero:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    orrs r0, r0, r1
+; CHECK-NEXT:    movwne r0, #1
+; CHECK-NEXT:    bx lr
+  %r = call i8 @llvm.ucmp.i8.i64(i64 %x, i64 0)
+  ret i8 %r
+}
+
+define i8 @ucmp_i128_zero_to_i8(i128 %x) nounwind {
+; CHECK-LABEL: ucmp_i128_zero_to_i8:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    orr r1, r1, r3
+; CHECK-NEXT:    orr r0, r0, r2
+; CHECK-NEXT:    orrs r0, r0, r1
+; CHECK-NEXT:    movwne r0, #1
+; CHECK-NEXT:    bx lr
+  %r = call i8 @llvm.ucmp.i8.i128(i128 %x, i128 0)
+  ret i8 %r
+}
diff --git a/llvm/test/CodeGen/LoongArch/scmp.ll b/llvm/test/CodeGen/LoongArch/scmp.ll
index 3c5f7aa27756c..b615b143d65a2 100644
--- a/llvm/test/CodeGen/LoongArch/scmp.ll
+++ b/llvm/test/CodeGen/LoongArch/scmp.ll
@@ -103,7 +103,6 @@ define i64 @scmp.64.64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
 define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: sext_scmp_i32:
 ; CHECK:       # %bb.0:
diff --git a/llvm/test/CodeGen/LoongArch/ucmp.ll b/llvm/test/CodeGen/LoongArch/ucmp.ll
index b952cd51c798f..f89eb0ed240da 100644
--- a/llvm/test/CodeGen/LoongArch/ucmp.ll
+++ b/llvm/test/CodeGen/LoongArch/ucmp.ll
@@ -103,7 +103,6 @@ define i64 @ucmp.64.64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
 define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: sext_ucmp_i32:
 ; CHECK:       # %bb.0:
@@ -117,3 +116,22 @@ define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
   %ext = sext i8 %cmp to i32
   ret i32 %ext
 }
+
+define i8 @ucmp_i64_zero(i64 %x) nounwind {
+; CHECK-LABEL: ucmp_i64_zero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    sltu $a0, $zero, $a0
+; CHECK-NEXT:    ret
+  %r = call i8 @llvm.ucmp.i8.i64(i64 %x, i64 0)
+  ret i8 %r
+}
+
+define i8 @ucmp_i128_zero_to_i8(i128 %x) nounwind {
+; CHECK-LABEL: ucmp_i128_zero_to_i8:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    or $a0, $a0, $a1
+; CHECK-NEXT:    sltu $a0, $zero, $a0
+; CHECK-NEXT:    ret
+  %r = call i8 @llvm.ucmp.i8.i128(i128 %x, i128 0)
+  ret i8 %r
+}
diff --git a/llvm/test/CodeGen/PowerPC/scmp.ll b/llvm/test/CodeGen/PowerPC/scmp.ll
index 1e7f7e7691fed..0ef557b011fab 100644
--- a/llvm/test/CodeGen/PowerPC/scmp.ll
+++ b/llvm/test/CodeGen/PowerPC/scmp.ll
@@ -126,7 +126,6 @@ define i64 @scmp_64_64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
 define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: sext_scmp_i32:
 ; CHECK:       # %bb.0:
diff --git a/llvm/test/CodeGen/PowerPC/ucmp.ll b/llvm/test/CodeGen/PowerPC/ucmp.ll
index cacfebc4bfba8..155358d4da65e 100644
--- a/llvm/test/CodeGen/PowerPC/ucmp.ll
+++ b/llvm/test/CodeGen/PowerPC/ucmp.ll
@@ -113,7 +113,6 @@ define i64 @ucmp_64_64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
 define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: sext_ucmp_i32:
 ; CHECK:       # %bb.0:
@@ -129,3 +128,26 @@ define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
   %ext = sext i8 %cmp to i32
   ret i32 %ext
 }
+
+define i8 @ucmp_i64_zero(i64 %x) nounwind {
+; CHECK-LABEL: ucmp_i64_zero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    subfic 4, 3, 0
+; CHECK-NEXT:    li 4, 0
+; CHECK-NEXT:    subfe 4, 4, 3
+; CHECK-NEXT:    subfe 3, 4, 3
+; CHECK-NEXT:    blr
+  %r = call i8 @llvm.ucmp.i8.i64(i64 %x, i64 0)
+  ret i8 %r
+}
+
+define i8 @ucmp_i128_zero_to_i8(i128 %x) nounwind {
+; CHECK-LABEL: ucmp_i128_zero_to_i8:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    or 3, 3, 4
+; CHECK-NEXT:    addic 4, 3, -1
+; CHECK-NEXT:    subfe 3, 4, 3
+; CHECK-NEXT:    blr
+  %r = call i8 @llvm.ucmp.i8.i128(i128 %x, i128 0)
+  ret i8 %r
+}
diff --git a/llvm/test/CodeGen/RISCV/scmp.ll b/llvm/test/CodeGen/RISCV/scmp.ll
index df572c75819b8..d57d859c8a72a 100644
--- a/llvm/test/CodeGen/RISCV/scmp.ll
+++ b/llvm/test/CodeGen/RISCV/scmp.ll
@@ -223,7 +223,6 @@ define i64 @scmp.64.64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
 define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
 ; RV32I-LABEL: sext_scmp_i32:
 ; RV32I:       # %bb.0:
diff --git a/llvm/test/CodeGen/RISCV/ucmp.ll b/llvm/test/CodeGen/RISCV/ucmp.ll
index 5e666d852bab3..acbd10a28c093 100644
--- a/llvm/test/CodeGen/RISCV/ucmp.ll
+++ b/llvm/test/CodeGen/RISCV/ucmp.ll
@@ -259,7 +259,6 @@ define i64 @ucmp.64.64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
 define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
 ; RV32I-LABEL: sext_ucmp_i32:
 ; RV32I:       # %bb.0:
@@ -280,3 +279,40 @@ define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
   %ext = sext i8 %cmp to i32
   ret i32 %ext
 }
+
+define i8 @ucmp_i64_zero(i64 %x) nounwind {
+; RV32I-LABEL: ucmp_i64_zero:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    or a0, a0, a1
+; RV32I-NEXT:    snez a0, a0
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: ucmp_i64_zero:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    snez a0, a0
+; RV64I-NEXT:    ret
+  %r = call i8 @llvm.ucmp.i8.i64(i64 %x, i64 0)
+  ret i8 %r
+}
+
+define i8 @ucmp_i128_zero_to_i8(i128 %x) nounwind {
+; RV32I-LABEL: ucmp_i128_zero_to_i8:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    lw a1, 4(a0)
+; RV32I-NEXT:    lw a2, 8(a0)
+; RV32I-NEXT:    lw a3, 12(a0)
+; RV32I-NEXT:    lw a0, 0(a0)
+; RV32I-NEXT:    or a1, a1, a3
+; RV32I-NEXT:    or a0, a0, a2
+; RV32I-NEXT:    or a0, a0, a1
+; RV32I-NEXT:    snez a0, a0
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: ucmp_i128_zero_to_i8:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    or a0, a0, a1
+; RV64I-NEXT:    snez a0, a0
+; RV64I-NEXT:    ret
+  %r = call i8 @llvm.ucmp.i8.i128(i128 %x, i128 0)
+  ret i8 %r
+}
diff --git a/llvm/test/CodeGen/SystemZ/scmp.ll b/llvm/test/CodeGen/SystemZ/scmp.ll
index 6caa2d9276777..c9f792d8efa67 100644
--- a/llvm/test/CodeGen/SystemZ/scmp.ll
+++ b/llvm/test/CodeGen/SystemZ/scmp.ll
@@ -108,7 +108,6 @@ define i64 @scmp.64.64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
 define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: sext_scmp_i32:
 ; CHECK:       # %bb.0:
diff --git a/llvm/test/CodeGen/SystemZ/ucmp.ll b/llvm/test/CodeGen/SystemZ/ucmp.ll
index 8906c34158539..dc70b9f744d32 100644
--- a/llvm/test/CodeGen/SystemZ/ucmp.ll
+++ b/llvm/test/CodeGen/SystemZ/ucmp.ll
@@ -108,7 +108,6 @@ define i64 @ucmp.64.64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
 define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: sext_ucmp_i32:
 ; CHECK:       # %bb.0:
@@ -121,3 +120,27 @@ define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
   %ext = sext i8 %cmp to i32
   ret i32 %ext
 }
+
+define i8 @ucmp_i64_zero(i64 %x) nounwind {
+; CHECK-LABEL: ucmp_i64_zero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    cghi %r2, 0
+; CHECK-NEXT:    lhi %r2, 0
+; CHECK-NEXT:    lochilh %r2, 1
+; CHECK-NEXT:    br %r14
+  %r = call i8 @llvm.ucmp.i8.i64(i64 %x, i64 0)
+  ret i8 %r
+}
+
+define i8 @ucmp_i128_zero_to_i8(i128 %x) nounwind {
+; CHECK-LABEL: ucmp_i128_zero_to_i8:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vl %v0, 0(%r2), 3
+; CHECK-NEXT:    vgbm %v1, 0
+; CHECK-NEXT:    vceqgs %v0, %v0, %v1
+; CHECK-NEXT:    lhi %r2, 0
+; CHECK-NEXT:    lochinhe %r2, 1
+; CHECK-NEXT:    br %r14
+  %r = call i8 @llvm.ucmp.i8.i128(i128 %x, i128 0)
+  ret i8 %r
+}
diff --git a/llvm/test/CodeGen/Thumb/scmp.ll b/llvm/test/CodeGen/Thumb/scmp.ll
index b9584e4168a6e..18389181601af 100644
--- a/llvm/test/CodeGen/Thumb/scmp.ll
+++ b/llvm/test/CodeGen/Thumb/scmp.ll
@@ -419,7 +419,6 @@ define i64 @scmp_64_64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
 define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
 ; THUMB1-LABEL: sext_scmp_i32:
 ; THUMB1:       @ %bb.0:
diff --git a/llvm/test/CodeGen/Thumb/ucmp.ll b/llvm/test/CodeGen/Thumb/ucmp.ll
index 8f09e581604f2..4202c340078e9 100644
--- a/llvm/test/CodeGen/Thumb/ucmp.ll
+++ b/llvm/test/CodeGen/Thumb/ucmp.ll
@@ -375,7 +375,6 @@ define i64 @ucmp_64_64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
 define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
 ; THUMB1-LABEL: sext_ucmp_i32:
 ; THUMB1:       @ %bb.0:
@@ -409,3 +408,57 @@ define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
   %ext = sext i8 %cmp to i32
   ret i32 %ext
 }
+
+define i8 @ucmp_i64_zero(i64 %x) nounwind {
+; THUMB1-LABEL: ucmp_i64_zero:
+; THUMB1:       @ %bb.0:
+; THUMB1-NEXT:    orrs r0, r1
+; THUMB1-NEXT:    subs r1, r0, #1
+; THUMB1-NEXT:    sbcs r0, r1
+; THUMB1-NEXT:    bx lr
+;
+; THUMB2-LABEL: ucmp_i64_zero:
+; THUMB2:       @ %bb.0:
+; THUMB2-NEXT:    orrs r0, r1
+; THUMB2-NEXT:    it ne
+; THUMB2-NEXT:    movne r0, #1
+; THUMB2-NEXT:    bx lr
+;
+; V81M-LABEL: ucmp_i64_zero:
+; V81M:       @ %bb.0:
+; V81M-NEXT:    orrs r0, r1
+; V81M-NEXT:    cset r0, ne
+; V81M-NEXT:    bx lr
+  %r = call i8 @llvm.ucmp.i8.i64(i64 %x, i64 0)
+  ret i8 %r
+}
+
+define i8 @ucmp_i128_zero_to_i8(i128 %x) nounwind {
+; THUMB1-LABEL: ucmp_i128_zero_to_i8:
+; THUMB1:       @ %bb.0:
+; THUMB1-NEXT:    orrs r1, r3
+; THUMB1-NEXT:    orrs r0, r2
+; THUMB1-NEXT:    orrs r0, r1
+; THUMB1-NEXT:    subs r1, r0, #1
+; THUMB1-NEXT:    sbcs r0, r1
+; THUMB1-NEXT:    bx lr
+;
+; THUMB2-LABEL: ucmp_i128_zero_to_i8:
+; THUMB2:       @ %bb.0:
+; THUMB2-NEXT:    orrs r1, r3
+; THUMB2-NEXT:    orrs r0, r2
+; THUMB2-NEXT:    orrs r0, r1
+; THUMB2-NEXT:    it ne
+; THUMB2-NEXT:    movne r0, #1
+; THUMB2-NEXT:    bx lr
+;
+; V81M-LABEL: ucmp_i128_zero_to_i8:
+; V81M:       @ %bb.0:
+; V81M-NEXT:    orrs r1, r3
+; V81M-NEXT:    orrs r0, r2
+; V81M-NEXT:    orrs r0, r1
+; V81M-NEXT:    cset r0, ne
+; V81M-NEXT:    bx lr
+  %r = call i8 @llvm.ucmp.i8.i128(i128 %x, i128 0)
+  ret i8 %r
+}
diff --git a/llvm/test/CodeGen/WebAssembly/scmp.ll b/llvm/test/CodeGen/WebAssembly/scmp.ll
index c02e47dac265f..90d90c41a3878 100644
--- a/llvm/test/CodeGen/WebAssembly/scmp.ll
+++ b/llvm/test/CodeGen/WebAssembly/scmp.ll
@@ -146,7 +146,6 @@ define i64 @scmp.64.64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
 define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: sext_scmp_i32:
 ; CHECK:         .functype sext_scmp_i32 (i32, i32) -> (i32)
diff --git a/llvm/test/CodeGen/WebAssembly/ucmp.ll b/llvm/test/CodeGen/WebAssembly/ucmp.ll
index 6f6456d9f9df5..9fce735f6ecc1 100644
--- a/llvm/test/CodeGen/WebAssembly/ucmp.ll
+++ b/llvm/test/CodeGen/WebAssembly/ucmp.ll
@@ -146,7 +146,6 @@ define i64 @ucmp.64.64(i64 %x, i64 %y) nounwind {
   ret i64 %1
 }
 
-; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
 define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
 ; CHECK-LABEL: sext_ucmp_i32:
 ; CHECK:         .functype sext_ucmp_i32 (i32, i32) -> (i32)
@@ -163,3 +162,29 @@ define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
   %ext = sext i8 %cmp to i32
   ret i32 %ext
 }
+
+define i8 @ucmp_i64_zero(i64 %x) nounwind {
+; CHECK-LABEL: ucmp_i64_zero:
+; CHECK:         .functype ucmp_i64_zero (i64) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get $push2=, 0
+; CHECK-NEXT:    i64.const $push0=, 0
+; CHECK-NEXT:    i64.ne $push1=, $pop2, $pop0
+; CHECK-NEXT:    # fallthrough-return
+  %r = call i8 @llvm.ucmp.i8.i64(i64 %x, i64 0)
+  ret i8 %r
+}
+
+define i8 @ucmp_i128_zero_to_i8(i128 %x) nounwind {
+; CHECK-LABEL: ucmp_i128_zero_to_i8:
+; CHECK:         .functype ucmp_i128_zero_to_i8 (i64, i64) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get $push4=, 0
+; CHECK-NEXT:    local.get $push3=, 1
+; CHECK-NEXT:    i64.or $push0=, $pop4, $pop3
+; CHECK-NEXT:    i64.const $push1=, 0
+; CHECK-NEXT:    i64.ne $push2=, $pop0, $pop1
+; CHECK-NEXT:    # fallthrough-return
+  %r = call i8 @llvm.ucmp.i8.i128(i128 %x, i128 0)
+  ret i8 %r
+}
diff --git a/llvm/test/CodeGen/X86/scmp.ll b/llvm/test/CodeGen/X86/scmp.ll
index 475b31e2c2f80..dc0951b0b71d3 100644
--- a/llvm/test/CodeGen/X86/scmp.ll
+++ b/llvm/test/CodeGen/X86/scmp.ll
@@ -3843,8 +3843,6 @@ define <2 x i16> @scmp_ret_wider_than_operands(<2 x i8> %x, <2 x i8> %y) nounwin
 }
 
 
-; InstCombine folds sext(scmp(x, 0)) -> scmp(x, 0) with a wider result type,
-; then expandCMP lowers the wider scmp to or(sra(x, bw-1), zext(setne(x, 0))).
 define i128 @sext_scmp_i128_zero(i128 %x) nounwind {
 ; X64-LABEL: sext_scmp_i128_zero:
 ; X64:       # %bb.0:
@@ -3897,9 +3895,6 @@ define i128 @sext_scmp_i128_zero(i128 %x) nounwind {
   ret i128 %ext
 }
 
-; InstCombine folds sext(scmp(x, 0)) -> scmp(x, 0) with i64 result type,
-; then expandCMP lowers the wider scmp to or(sra(x, bw-1), zext(setne(x, 0)))
-; truncated to i64.
 define i64 @sext_scmp_i128_to_i64(i128 %x) nounwind {
 ; X64-LABEL: sext_scmp_i128_to_i64:
 ; X64:       # %bb.0:
@@ -3946,7 +3941,6 @@ define i64 @sext_scmp_i128_to_i64(i128 %x) nounwind {
   ret i64 %ext
 }
 
-; bare scmp(x, 0) returning narrow type folds via expandCMP.
 define i8 @scmp_i128_zero_to_i8(i128 %x) nounwind {
 ; X64-LABEL: scmp_i128_zero_to_i8:
 ; X64:       # %bb.0:
@@ -3993,7 +3987,6 @@ define i8 @scmp_i128_zero_to_i8(i128 %x) nounwind {
   ret i8 %r
 }
 
-; sext(scmp(x, y)) folds in InstCombine to scmp with a wider result type.
 define i32 @sext_scmp_i32(i32 %x, i32 %y) nounwind {
 ; X64-LABEL: sext_scmp_i32:
 ; X64:       # %bb.0:
diff --git a/llvm/test/CodeGen/X86/ucmp.ll b/llvm/test/CodeGen/X86/ucmp.ll
index c6ffbd14fd4b6..6c0561ee8e9eb 100644
--- a/llvm/test/CodeGen/X86/ucmp.ll
+++ b/llvm/test/CodeGen/X86/ucmp.ll
@@ -3392,7 +3392,6 @@ define <17 x i2> @ucmp_uncommon_vectors(<17 x i71> %x, <17 x i71> %y) nounwind {
   ret <17 x i2> %1
 }
 
-; sext(ucmp(x, y)) folds in InstCombine to ucmp with a wider result type.
 define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
 ; X64-LABEL: sext_ucmp_i32:
 ; X64:       # %bb.0:
@@ -3414,3 +3413,113 @@ define i32 @sext_ucmp_i32(i32 %x, i32 %y) nounwind {
   %ext = sext i8 %cmp to i32
   ret i32 %ext
 }
+
+define i8 @ucmp_i64_zero(i64 %x) nounwind {
+; X64-LABEL: ucmp_i64_zero:
+; X64:       # %bb.0:
+; X64-NEXT:    testq %rdi, %rdi
+; X64-NEXT:    setne %al
+; X64-NEXT:    retq
+;
+; X86-LABEL: ucmp_i64_zero:
+; X86:       # %bb.0:
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    orl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    setne %al
+; X86-NEXT:    retl
+  %r = call i8 @llvm.ucmp.i8.i64(i64 %x, i64 0)
+  ret i8 %r
+}
+
+define i8 @ucmp_i128_zero_to_i8(i128 %x) nounwind {
+; X64-LABEL: ucmp_i128_zero_to_i8:
+; X64:       # %bb.0:
+; X64-NEXT:    orq %rsi, %rdi
+; X64-NEXT:    setne %al
+; X64-NEXT:    retq
+;
+; X86-LABEL: ucmp_i128_zero_to_i8:
+; X86:       # %bb.0:
+; X86-NEXT:    pushl %ebp
+; X86-NEXT:    movl %esp, %ebp
+; X86-NEXT:    andl $-16, %esp
+; X86-NEXT:    subl $16, %esp
+; X86-NEXT:    movl 8(%ebp), %eax
+; X86-NEXT:    movl 12(%ebp), %ecx
+; X86-NEXT:    orl 20(%ebp), %ecx
+; X86-NEXT:    orl 16(%ebp), %eax
+; X86-NEXT:    orl %ecx, %eax
+; X86-NEXT:    setne %al
+; X86-NEXT:    movl %ebp, %esp
+; X86-NEXT:    popl %ebp
+; X86-NEXT:    retl
+  %r = call i8 @llvm.ucmp.i8.i128(i128 %x, i128 0)
+  ret i8 %r
+}
+
+define i128 @sext_ucmp_i128_zero(i128 %x) nounwind {
+; X64-LABEL: sext_ucmp_i128_zero:
+; X64:       # %bb.0:
+; X64-NEXT:    xorl %eax, %eax
+; X64-NEXT:    orq %rsi, %rdi
+; X64-NEXT:    setne %al
+; X64-NEXT:    xorl %edx, %edx
+; X64-NEXT:    retq
+;
+; X86-LABEL: sext_ucmp_i128_zero:
+; X86:       # %bb.0:
+; X86-NEXT:    pushl %ebp
+; X86-NEXT:    movl %esp, %ebp
+; X86-NEXT:    pushl %ebx
+; X86-NEXT:    andl $-16, %esp
+; X86-NEXT:    subl $16, %esp
+; X86-NEXT:    movl 8(%ebp), %eax
+; X86-NEXT:    movl 24(%ebp), %ecx
+; X86-NEXT:    movl 28(%ebp), %edx
+; X86-NEXT:    orl 36(%ebp), %edx
+; X86-NEXT:    orl 32(%ebp), %ecx
+; X86-NEXT:    xorl %ebx, %ebx
+; X86-NEXT:    orl %edx, %ecx
+; X86-NEXT:    setne %bl
+; X86-NEXT:    movl %ebx, (%eax)
+; X86-NEXT:    movl $0, 12(%eax)
+; X86-NEXT:    movl $0, 8(%eax)
+; X86-NEXT:    movl $0, 4(%eax)
+; X86-NEXT:    leal -4(%ebp), %esp
+; X86-NEXT:    popl %ebx
+; X86-NEXT:    popl %ebp
+; X86-NEXT:    retl $4
+  %cmp = call i8 @llvm.ucmp.i8.i128(i128 %x, i128 0)
+  %ext = sext i8 %cmp to i128
+  ret i128 %ext
+}
+
+define i64 @sext_ucmp_i128_to_i64(i128 %x) nounwind {
+; X64-LABEL: sext_ucmp_i128_to_i64:
+; X64:       # %bb.0:
+; X64-NEXT:    xorl %eax, %eax
+; X64-NEXT:    orq %rsi, %rdi
+; X64-NEXT:    setne %al
+; X64-NEXT:    retq
+;
+; X86-LABEL: sext_ucmp_i128_to_i64:
+; X86:       # %bb.0:
+; X86-NEXT:    pushl %ebp
+; X86-NEXT:    movl %esp, %ebp
+; X86-NEXT:    andl $-16, %esp
+; X86-NEXT:    subl $16, %esp
+; X86-NEXT:    movl 8(%ebp), %ecx
+; X86-NEXT:    movl 12(%ebp), %edx
+; X86-NEXT:    orl 20(%ebp), %edx
+; X86-NEXT:    orl 16(%ebp), %ecx
+; X86-NEXT:    xorl %eax, %eax
+; X86-NEXT:    orl %edx, %ecx
+; X86-NEXT:    setne %al
+; X86-NEXT:    xorl %edx, %edx
+; X86-NEXT:    movl %ebp, %esp
+; X86-NEXT:    popl %ebp
+; X86-NEXT:    retl
+  %cmp = call i8 @llvm.ucmp.i8.i128(i128 %x, i128 0)
+  %ext = sext i8 %cmp to i64
+  ret i64 %ext
+}
diff --git a/llvm/test/Transforms/InstCombine/scmp.ll b/llvm/test/Transforms/InstCombine/scmp.ll
index 2a5cb151aa008..871b56c15d18b 100644
--- a/llvm/test/Transforms/InstCombine/scmp.ll
+++ b/llvm/test/Transforms/InstCombine/scmp.ll
@@ -798,7 +798,6 @@ define i8 @scmp_ashr_slt_pattern_neg(i8 %a) {
   ret i8 %retval
 }
 
-; sext(scmp(x, y)) folds to a scmp with a wider result type.
 define i64 @sext_scmp(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i64 @sext_scmp(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
diff --git a/llvm/test/Transforms/InstCombine/ucmp.ll b/llvm/test/Transforms/InstCombine/ucmp.ll
index bc912d7850e83..3b23cde0b00bd 100644
--- a/llvm/test/Transforms/InstCombine/ucmp.ll
+++ b/llvm/test/Transforms/InstCombine/ucmp.ll
@@ -556,7 +556,6 @@ define i8 @scmp_from_select_eq_and_gt(i32 %x, i32 %y) {
   ret i8 %r
 }
 
-; sext(ucmp(x, y)) folds to a ucmp with a wider result type.
 define i64 @sext_ucmp(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i64 @sext_ucmp(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {



More information about the llvm-commits mailing list