[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