[clang] [llvm] [InstCombine] Fold select(X >s 0, 0, -X) | smax(X, 0) to abs(X) (PR #165200)

Wenju He via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 29 16:55:43 PDT 2025


https://github.com/wenju-he updated https://github.com/llvm/llvm-project/pull/165200

>From 4629547485d5b0c4f0a0e3e2e026222bbb654c7a Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Mon, 27 Oct 2025 05:41:34 +0100
Subject: [PATCH 1/9] [InstCombine] Fold select(X >s 0, 0, -X) | smax(X, 0) to
 abs(X)

The IR pattern is compiled from OpenCL code:
  __builtin_astype(x > (uchar2)(0) ? x : -x, uchar2);
where smax is created by foldSelectInstWithICmp + canonicalizeSPF.

smax could also come from direct elementwise max call:
  int c = b > (int)(0) ? (int)(0) : -b;
  int d = __builtin_elementwise_max(b, (int)(0));
  *a = c | d;
---
 .../InstCombine/InstCombineAndOrXor.cpp       | 18 ++++++++++++
 llvm/test/Transforms/InstCombine/or.ll        | 28 +++++++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 3ddf182149e57..4e863ca2c6dfd 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3997,6 +3997,20 @@ static Value *foldOrUnsignedUMulOverflowICmp(BinaryOperator &I,
   return nullptr;
 }
 
+// Fold select(X >s 0, 0, -X) | smax(X, 0) --> abs(X)
+static Value *FoldOrOfSelectSmaxToAbs(BinaryOperator &I,
+                                      InstCombiner::BuilderTy &Builder) {
+  CmpPredicate Pred;
+  Value *X;
+  if (match(&I, m_c_Or(m_Select(m_ICmp(Pred, m_Value(X), m_ZeroInt()),
+                                m_ZeroInt(), m_Sub(m_ZeroInt(), m_Deferred(X))),
+                       m_OneUse(m_Intrinsic<Intrinsic::smax>(m_Deferred(X),
+                                                             m_ZeroInt())))) &&
+      Pred == ICmpInst::ICMP_SGT)
+    return Builder.CreateBinaryIntrinsic(Intrinsic::abs, X, Builder.getFalse());
+  return nullptr;
+}
+
 // FIXME: We use commutative matchers (m_c_*) for some, but not all, matches
 // here. We should standardize that construct where it is needed or choose some
 // other way to ensure that commutated variants of patterns are not missed.
@@ -4545,6 +4559,10 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
     if (Value *V = SimplifyAddWithRemainder(I))
       return replaceInstUsesWith(I, V);
 
+  // select(X >s 0, 0, -X) | smax(X, 0) -> abs(X)
+  if (Value *Res = FoldOrOfSelectSmaxToAbs(I, Builder))
+    return replaceInstUsesWith(I, Res);
+
   return nullptr;
 }
 
diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index 6b090e982af0a..bbc79e8c16a56 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -2113,3 +2113,31 @@ define <4 x i32> @or_zext_nneg_minus_constant_splat(<4 x i8> %a) {
   %or = or <4 x i32> %zext, splat (i32 -9)
   ret <4 x i32> %or
 }
+
+define i8 @or_positive_minus_non_positive_to_abs(i8 noundef %0){
+; CHECK-LABEL: @or_positive_minus_non_positive_to_abs(
+; CHECK-NEXT:    [[TMP2:%.*]] = call i8 @llvm.abs.i8(i8 [[TMP0:%.*]], i1 false)
+; CHECK-NEXT:    ret i8 [[TMP2]]
+;
+  %2 = icmp sgt i8 %0, zeroinitializer
+  %3 = sext i1 %2 to i8
+  %4 = sub i8 zeroinitializer, %0
+  %5 = xor i8 %3, -1
+  %6 = and i8 %4, %5
+  %7 = and i8 %0, %3
+  %8 = or i8 %6, %7
+  ret i8 %8
+}
+
+define <2 x i8> @or_select_smax_to_abs(<2 x i8> %0){
+; CHECK-LABEL: @or_select_smax_to_abs(
+; CHECK-NEXT:    [[TMP2:%.*]] = call <2 x i8> @llvm.abs.v2i8(<2 x i8> [[TMP0:%.*]], i1 false)
+; CHECK-NEXT:    ret <2 x i8> [[TMP2]]
+;
+  %2 = icmp sgt <2 x i8> %0, zeroinitializer
+  %3 = sub <2 x i8> zeroinitializer, %0
+  %4 = select <2 x i1> %2, <2 x i8> zeroinitializer, <2 x i8> %3
+  %5 = tail call <2 x i8> @llvm.smax.v2i8(<2 x i8> %0, <2 x i8> zeroinitializer)
+  %6 = or <2 x i8> %4, %5
+  ret <2 x i8> %6
+}

>From af62083f6139ac5c103e8342e8ed6a7c877edfb9 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Mon, 27 Oct 2025 07:32:30 +0100
Subject: [PATCH 2/9] named value, add negative test with multiple uses of
 @llvm.smax

---
 llvm/test/Transforms/InstCombine/or.ll | 55 ++++++++++++++++++--------
 1 file changed, 39 insertions(+), 16 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index bbc79e8c16a56..dcc8a712cd835 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -2114,30 +2114,53 @@ define <4 x i32> @or_zext_nneg_minus_constant_splat(<4 x i8> %a) {
   ret <4 x i32> %or
 }
 
-define i8 @or_positive_minus_non_positive_to_abs(i8 noundef %0){
+define i8 @or_positive_minus_non_positive_to_abs(i8 %a){
 ; CHECK-LABEL: @or_positive_minus_non_positive_to_abs(
 ; CHECK-NEXT:    [[TMP2:%.*]] = call i8 @llvm.abs.i8(i8 [[TMP0:%.*]], i1 false)
 ; CHECK-NEXT:    ret i8 [[TMP2]]
 ;
-  %2 = icmp sgt i8 %0, zeroinitializer
-  %3 = sext i1 %2 to i8
-  %4 = sub i8 zeroinitializer, %0
-  %5 = xor i8 %3, -1
-  %6 = and i8 %4, %5
-  %7 = and i8 %0, %3
-  %8 = or i8 %6, %7
-  ret i8 %8
+  %b = icmp sgt i8 %a, zeroinitializer
+  %mask = sext i1 %b to i8
+  %neg = sub i8 zeroinitializer, %a
+  %mask_inv = xor i8 %mask, -1
+  %c = and i8 %neg, %mask_inv
+  %d = and i8 %a, %mask
+  %or = or i8 %c, %d
+  ret i8 %or
 }
 
-define <2 x i8> @or_select_smax_to_abs(<2 x i8> %0){
+define <2 x i8> @or_select_smax_to_abs(<2 x i8> %a){
 ; CHECK-LABEL: @or_select_smax_to_abs(
 ; CHECK-NEXT:    [[TMP2:%.*]] = call <2 x i8> @llvm.abs.v2i8(<2 x i8> [[TMP0:%.*]], i1 false)
 ; CHECK-NEXT:    ret <2 x i8> [[TMP2]]
 ;
-  %2 = icmp sgt <2 x i8> %0, zeroinitializer
-  %3 = sub <2 x i8> zeroinitializer, %0
-  %4 = select <2 x i1> %2, <2 x i8> zeroinitializer, <2 x i8> %3
-  %5 = tail call <2 x i8> @llvm.smax.v2i8(<2 x i8> %0, <2 x i8> zeroinitializer)
-  %6 = or <2 x i8> %4, %5
-  ret <2 x i8> %6
+  %sgt0 = icmp sgt <2 x i8> %a, zeroinitializer
+  %neg = sub <2 x i8> zeroinitializer, %a
+  %sel = select <2 x i1> %sgt0, <2 x i8> zeroinitializer, <2 x i8> %neg
+  %max = call <2 x i8> @llvm.smax.v2i8(<2 x i8> %a, <2 x i8> zeroinitializer)
+  %or = or <2 x i8> %sel, %max
+  ret <2 x i8> %or
+}
+
+declare <2 x i8> @llvm.abs.v2i8(<2 x i8>, i1)
+
+; negative test - %d has multiple uses. %or is not folded to abs.
+
+define <2 x i8> @or_select_smax_multi_uses(<2 x i8> %a){
+; CHECK-LABEL: @or_select_smax_multi_uses(
+; CHECK-NEXT:    [[B:%.*]] = icmp sgt <2 x i8> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    [[NEG:%.*]] = sub <2 x i8> zeroinitializer, [[A]]
+; CHECK-NEXT:    [[C:%.*]] = select <2 x i1> [[B]], <2 x i8> zeroinitializer, <2 x i8> [[NEG]]
+; CHECK-NEXT:    [[D:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[A]], <2 x i8> zeroinitializer)
+; CHECK-NEXT:    [[OR1:%.*]] = or <2 x i8> [[C]], [[D]]
+; CHECK-NEXT:    [[OR:%.*]] = add <2 x i8> [[OR1]], [[D]]
+; CHECK-NEXT:    ret <2 x i8> [[OR]]
+;
+  %sgt0 = icmp sgt <2 x i8> %a, zeroinitializer
+  %neg = sub <2 x i8> zeroinitializer, %a
+  %sel = select <2 x i1> %sgt0, <2 x i8> zeroinitializer, <2 x i8> %neg
+  %max = call <2 x i8> @llvm.smax.v2i8(<2 x i8> %a, <2 x i8> zeroinitializer)
+  %or = or <2 x i8> %sel, %max
+  %e = add <2 x i8> %or, %max
+  ret <2 x i8> %e
 }

>From 21ca09a9ba1202f19c087ebf1f0f4bf369f21527 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Mon, 27 Oct 2025 07:35:16 +0100
Subject: [PATCH 3/9] rename %e -> %add

---
 llvm/test/Transforms/InstCombine/or.ll | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index dcc8a712cd835..61c1ac5f18a28 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -2161,6 +2161,6 @@ define <2 x i8> @or_select_smax_multi_uses(<2 x i8> %a){
   %sel = select <2 x i1> %sgt0, <2 x i8> zeroinitializer, <2 x i8> %neg
   %max = call <2 x i8> @llvm.smax.v2i8(<2 x i8> %a, <2 x i8> zeroinitializer)
   %or = or <2 x i8> %sel, %max
-  %e = add <2 x i8> %or, %max
-  ret <2 x i8> %e
+  %add = add <2 x i8> %or, %max
+  ret <2 x i8> %add
 }

>From 1e9a8cedf135cb04e02050a7e48c019674211915 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Tue, 28 Oct 2025 02:58:24 +0100
Subject: [PATCH 4/9] add TODO: fold to smax(neg, fold two smax

---
 llvm/test/Transforms/InstCombine/or.ll | 39 +++++++++++++++++++++++---
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index 61c1ac5f18a28..01fb9295b1e04 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -2119,9 +2119,9 @@ define i8 @or_positive_minus_non_positive_to_abs(i8 %a){
 ; CHECK-NEXT:    [[TMP2:%.*]] = call i8 @llvm.abs.i8(i8 [[TMP0:%.*]], i1 false)
 ; CHECK-NEXT:    ret i8 [[TMP2]]
 ;
-  %b = icmp sgt i8 %a, zeroinitializer
+  %b = icmp sgt i8 %a, 0
   %mask = sext i1 %b to i8
-  %neg = sub i8 zeroinitializer, %a
+  %neg = sub i8 0, %a
   %mask_inv = xor i8 %mask, -1
   %c = and i8 %neg, %mask_inv
   %d = and i8 %a, %mask
@@ -2129,6 +2129,39 @@ define i8 @or_positive_minus_non_positive_to_abs(i8 %a){
   ret i8 %or
 }
 
+; TODO Fold to smax https://alive2.llvm.org/ce/z/wDiDh2
+define i8 @or_select_smax_neg_to_abs(i8 %a){
+; CHECK-LABEL: @or_select_smax_neg_to_abs(
+; CHECK-NEXT:    [[SGT0:%.*]] = icmp sgt i8 [[A:%.*]], 0
+; CHECK-NEXT:    [[NEG:%.*]] = sub nsw i8 0, [[A]]
+; CHECK-NEXT:    [[OR:%.*]] = select i1 [[SGT0]], i8 0, i8 [[NEG]]
+; CHECK-NEXT:    ret i8 [[OR]]
+;
+  %sgt0 = icmp sgt i8 %a, 0
+  %neg = sub nsw i8 0, %a
+  %sel = select i1 %sgt0, i8 0, i8 %neg
+  ret i8 %sel
+}
+
+; TODO Fold to abs https://alive2.llvm.org/ce/z/DybfHG
+define i8 @or_select_smax_smax_to_abs(i8 %a){
+; CHECK-LABEL: @or_select_smax_smax_to_abs(
+; CHECK-NEXT:    [[NEG:%.*]] = sub nsw i8 0, [[A:%.*]]
+; CHECK-NEXT:    [[SEL:%.*]] = call i8 @llvm.smax.i8(i8 [[NEG]], i8 0)
+; CHECK-NEXT:    [[MAX:%.*]] = call i8 @llvm.smax.i8(i8 [[A]], i8 0)
+; CHECK-NEXT:    [[OR:%.*]] = or i8 [[SEL]], [[MAX]]
+; CHECK-NEXT:    ret i8 [[OR]]
+;
+  %neg = sub nsw i8 0, %a
+  %sel = call i8 @llvm.smax.i8(i8 %neg, i8 0)
+  %max = call i8 @llvm.smax.i8(i8 %a, i8 0)
+  %or = or i8 %sel, %max
+  ret i8 %or
+}
+
+declare i8 @llvm.abs.i8(i8, i1)
+declare <2 x i8> @llvm.abs.v2i8(<2 x i8>, i1)
+
 define <2 x i8> @or_select_smax_to_abs(<2 x i8> %a){
 ; CHECK-LABEL: @or_select_smax_to_abs(
 ; CHECK-NEXT:    [[TMP2:%.*]] = call <2 x i8> @llvm.abs.v2i8(<2 x i8> [[TMP0:%.*]], i1 false)
@@ -2142,8 +2175,6 @@ define <2 x i8> @or_select_smax_to_abs(<2 x i8> %a){
   ret <2 x i8> %or
 }
 
-declare <2 x i8> @llvm.abs.v2i8(<2 x i8>, i1)
-
 ; negative test - %d has multiple uses. %or is not folded to abs.
 
 define <2 x i8> @or_select_smax_multi_uses(<2 x i8> %a){

>From e5d284b1565a2d8a43f82b35b72a52373583daee Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Tue, 28 Oct 2025 10:01:14 +0800
Subject: [PATCH 5/9] Update
 llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Co-authored-by: Yingwei Zheng <dtcxzyw at qq.com>
---
 llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 4e863ca2c6dfd..66fc6bbadfceb 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3997,7 +3997,7 @@ static Value *foldOrUnsignedUMulOverflowICmp(BinaryOperator &I,
   return nullptr;
 }
 
-// Fold select(X >s 0, 0, -X) | smax(X, 0) --> abs(X)
+/// Fold select(X >s 0, 0, -X) | smax(X, 0) --> abs(X)
 static Value *FoldOrOfSelectSmaxToAbs(BinaryOperator &I,
                                       InstCombiner::BuilderTy &Builder) {
   CmpPredicate Pred;

>From e19950b0ee10e926deb1afa17fd7219eb0b26a0e Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Tue, 28 Oct 2025 10:01:26 +0800
Subject: [PATCH 6/9] Update
 llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Co-authored-by: Yingwei Zheng <dtcxzyw at qq.com>
---
 llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 66fc6bbadfceb..a0cd19195cb9f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -4002,11 +4002,10 @@ static Value *FoldOrOfSelectSmaxToAbs(BinaryOperator &I,
                                       InstCombiner::BuilderTy &Builder) {
   CmpPredicate Pred;
   Value *X;
-  if (match(&I, m_c_Or(m_Select(m_ICmp(Pred, m_Value(X), m_ZeroInt()),
+  if (match(&I, m_c_Or(m_Select(m_SpecificICmp(ICmpInst::ICMP_SGT, m_Value(X), m_ZeroInt()),
                                 m_ZeroInt(), m_Sub(m_ZeroInt(), m_Deferred(X))),
                        m_OneUse(m_Intrinsic<Intrinsic::smax>(m_Deferred(X),
-                                                             m_ZeroInt())))) &&
-      Pred == ICmpInst::ICMP_SGT)
+                                                             m_ZeroInt())))))
     return Builder.CreateBinaryIntrinsic(Intrinsic::abs, X, Builder.getFalse());
   return nullptr;
 }

>From 28f198719042cefd3eb2ed65ef7e4836abcb5c07 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Tue, 28 Oct 2025 03:01:52 +0100
Subject: [PATCH 7/9] clang-format

---
 llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index a0cd19195cb9f..ddb4e89a22a7d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -4002,7 +4002,8 @@ static Value *FoldOrOfSelectSmaxToAbs(BinaryOperator &I,
                                       InstCombiner::BuilderTy &Builder) {
   CmpPredicate Pred;
   Value *X;
-  if (match(&I, m_c_Or(m_Select(m_SpecificICmp(ICmpInst::ICMP_SGT, m_Value(X), m_ZeroInt()),
+  if (match(&I, m_c_Or(m_Select(m_SpecificICmp(ICmpInst::ICMP_SGT, m_Value(X),
+                                               m_ZeroInt()),
                                 m_ZeroInt(), m_Sub(m_ZeroInt(), m_Deferred(X))),
                        m_OneUse(m_Intrinsic<Intrinsic::smax>(m_Deferred(X),
                                                              m_ZeroInt())))))

>From bd8b791294033a952e034ff47ec1f0a56d12f064 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Tue, 28 Oct 2025 03:37:07 +0100
Subject: [PATCH 8/9] select(X <s 0, -X, 0) | smax(X, 0) --> abs(X)

---
 .../InstCombine/InstCombineAndOrXor.cpp       | 22 +++++++++++-------
 llvm/test/Transforms/InstCombine/or.ll        | 23 +++++++++++++++----
 2 files changed, 32 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index ddb4e89a22a7d..952219a1d55cc 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3998,16 +3998,23 @@ static Value *foldOrUnsignedUMulOverflowICmp(BinaryOperator &I,
 }
 
 /// Fold select(X >s 0, 0, -X) | smax(X, 0) --> abs(X)
+///      select(X <s 0, -X, 0) | smax(X, 0) --> abs(X)
 static Value *FoldOrOfSelectSmaxToAbs(BinaryOperator &I,
                                       InstCombiner::BuilderTy &Builder) {
-  CmpPredicate Pred;
   Value *X;
-  if (match(&I, m_c_Or(m_Select(m_SpecificICmp(ICmpInst::ICMP_SGT, m_Value(X),
-                                               m_ZeroInt()),
-                                m_ZeroInt(), m_Sub(m_ZeroInt(), m_Deferred(X))),
-                       m_OneUse(m_Intrinsic<Intrinsic::smax>(m_Deferred(X),
-                                                             m_ZeroInt())))))
-    return Builder.CreateBinaryIntrinsic(Intrinsic::abs, X, Builder.getFalse());
+  Value *Sel;
+  if (match(&I, m_c_Or(m_Value(Sel), m_OneUse(m_Intrinsic<Intrinsic::smax>(
+                                         m_Value(X), m_ZeroInt()))))) {
+    auto NegX = m_Neg(m_Specific(X));
+    if (match(Sel, m_Select(m_SpecificICmp(ICmpInst::ICMP_SGT, m_Specific(X),
+                                           m_ZeroInt()),
+                            m_ZeroInt(), NegX)) ||
+        match(Sel, m_Select(m_SpecificICmp(ICmpInst::ICMP_SLT, m_Specific(X),
+                                           m_ZeroInt()),
+                            NegX, m_ZeroInt())))
+      return Builder.CreateBinaryIntrinsic(Intrinsic::abs, X,
+                                           Builder.getFalse());
+  }
   return nullptr;
 }
 
@@ -4559,7 +4566,6 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
     if (Value *V = SimplifyAddWithRemainder(I))
       return replaceInstUsesWith(I, V);
 
-  // select(X >s 0, 0, -X) | smax(X, 0) -> abs(X)
   if (Value *Res = FoldOrOfSelectSmaxToAbs(I, Builder))
     return replaceInstUsesWith(I, Res);
 
diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index 01fb9295b1e04..9b473904757c9 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -2116,7 +2116,7 @@ define <4 x i32> @or_zext_nneg_minus_constant_splat(<4 x i8> %a) {
 
 define i8 @or_positive_minus_non_positive_to_abs(i8 %a){
 ; CHECK-LABEL: @or_positive_minus_non_positive_to_abs(
-; CHECK-NEXT:    [[TMP2:%.*]] = call i8 @llvm.abs.i8(i8 [[TMP0:%.*]], i1 false)
+; CHECK-NEXT:    [[TMP2:%.*]] = call i8 @llvm.abs.i8(i8 [[A:%.*]], i1 false)
 ; CHECK-NEXT:    ret i8 [[TMP2]]
 ;
   %b = icmp sgt i8 %a, 0
@@ -2162,10 +2162,10 @@ define i8 @or_select_smax_smax_to_abs(i8 %a){
 declare i8 @llvm.abs.i8(i8, i1)
 declare <2 x i8> @llvm.abs.v2i8(<2 x i8>, i1)
 
-define <2 x i8> @or_select_smax_to_abs(<2 x i8> %a){
-; CHECK-LABEL: @or_select_smax_to_abs(
-; CHECK-NEXT:    [[TMP2:%.*]] = call <2 x i8> @llvm.abs.v2i8(<2 x i8> [[TMP0:%.*]], i1 false)
-; CHECK-NEXT:    ret <2 x i8> [[TMP2]]
+define <2 x i8> @or_sgt_select_smax_to_abs(<2 x i8> %a){
+; CHECK-LABEL: @or_sgt_select_smax_to_abs(
+; CHECK-NEXT:    [[OR:%.*]] = call <2 x i8> @llvm.abs.v2i8(<2 x i8> [[A:%.*]], i1 false)
+; CHECK-NEXT:    ret <2 x i8> [[OR]]
 ;
   %sgt0 = icmp sgt <2 x i8> %a, zeroinitializer
   %neg = sub <2 x i8> zeroinitializer, %a
@@ -2175,6 +2175,19 @@ define <2 x i8> @or_select_smax_to_abs(<2 x i8> %a){
   ret <2 x i8> %or
 }
 
+define <2 x i8> @or_lgt_select_smax_to_abs(<2 x i8> %a){
+; CHECK-LABEL: @or_lgt_select_smax_to_abs(
+; CHECK-NEXT:    [[OR:%.*]] = call <2 x i8> @llvm.abs.v2i8(<2 x i8> [[A:%.*]], i1 false)
+; CHECK-NEXT:    ret <2 x i8> [[OR]]
+;
+  %slt0 = icmp slt <2 x i8> %a, zeroinitializer
+  %neg = sub <2 x i8> zeroinitializer, %a
+  %sel = select <2 x i1> %slt0, <2 x i8> %neg, <2 x i8> zeroinitializer
+  %max = call <2 x i8> @llvm.smax.v2i8(<2 x i8> %a, <2 x i8> zeroinitializer)
+  %or = or <2 x i8> %sel, %max
+  ret <2 x i8> %or
+}
+
 ; negative test - %d has multiple uses. %or is not folded to abs.
 
 define <2 x i8> @or_select_smax_multi_uses(<2 x i8> %a){

>From 154c2c113344623821bd0288d113a8b67b14478c Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Tue, 28 Oct 2025 05:24:45 +0100
Subject: [PATCH 9/9] update
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c

---
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c  | 8 ++++----
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
index d5d15b4dea966..35fde8733f375 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
@@ -3584,13 +3584,13 @@ void test_integer(void) {
   // CHECK-ASM: vsrlb
 
   vsc = vec_abs(vsc);
-  // CHECK-ASM: vlcb
+  // CHECK-ASM: vlpb
   vss = vec_abs(vss);
-  // CHECK-ASM: vlch
+  // CHECK-ASM: vlph
   vsi = vec_abs(vsi);
-  // CHECK-ASM: vlcf
+  // CHECK-ASM: vlpf
   vsl = vec_abs(vsl);
-  // CHECK-ASM: vlcg
+  // CHECK-ASM: vlpg
 
   vsc = vec_max(vsc, vsc);
   // CHECK-ASM: vmxb
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c
index 6ee9e1ee3a117..cd0fafdb7435f 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c
@@ -246,7 +246,7 @@ void test_integer(void) {
   // CHECK-ASM: vctzq
 
   vslll = vec_abs(vslll);
-  // CHECK-ASM: vlcq
+  // CHECK-ASM: vlpq
 
   vslll = vec_avg(vslll, vslll);
   // CHECK: call i128 @llvm.s390.vavgq(i128 %{{.*}}, i128 %{{.*}})



More information about the cfe-commits mailing list