From 4629547485d5b0c4f0a0e3e2e026222bbb654c7a Mon Sep 17 00:00:00 2001 From: Wenju He Date: Mon, 27 Oct 2025 05:41:34 +0100 Subject: [PATCH 01/12] [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(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 Date: Mon, 27 Oct 2025 07:32:30 +0100 Subject: [PATCH 02/12] 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 Date: Mon, 27 Oct 2025 07:35:16 +0100 Subject: [PATCH 03/12] 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 Date: Tue, 28 Oct 2025 02:58:24 +0100 Subject: [PATCH 04/12] 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 Date: Tue, 28 Oct 2025 10:01:14 +0800 Subject: [PATCH 05/12] Update llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp Co-authored-by: Yingwei Zheng --- 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 Date: Tue, 28 Oct 2025 10:01:26 +0800 Subject: [PATCH 06/12] Update llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp Co-authored-by: Yingwei Zheng --- 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(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 Date: Tue, 28 Oct 2025 03:01:52 +0100 Subject: [PATCH 07/12] 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(m_Deferred(X), m_ZeroInt()))))) From bd8b791294033a952e034ff47ec1f0a56d12f064 Mon Sep 17 00:00:00 2001 From: Wenju He Date: Tue, 28 Oct 2025 03:37:07 +0100 Subject: [PATCH 08/12] select(X 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 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(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( + 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 Date: Tue, 28 Oct 2025 05:24:45 +0100 Subject: [PATCH 09/12] 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 %{{.*}}) From c01eb5a2bebb40c14a693e1cdee79126ecb76421 Mon Sep 17 00:00:00 2001 From: Wenju He Date: Fri, 31 Oct 2025 00:17:00 +0100 Subject: [PATCH 10/12] rename or_lgt_select_smax_to_abs -> or_slt_select_smax_to_abs --- 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 9b473904757c9..aeb42744b6838 100644 --- a/llvm/test/Transforms/InstCombine/or.ll +++ b/llvm/test/Transforms/InstCombine/or.ll @@ -2175,8 +2175,8 @@ define <2 x i8> @or_sgt_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( +define <2 x i8> @or_slt_select_smax_to_abs(<2 x i8> %a){ +; CHECK-LABEL: @or_slt_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]] ; From 4c92c7c77f835069198e33d3a39220df8e728bc8 Mon Sep 17 00:00:00 2001 From: Wenju He Date: Fri, 31 Oct 2025 15:32:22 +0800 Subject: [PATCH 11/12] Update llvm/test/Transforms/InstCombine/or.ll Co-authored-by: Matt Arsenault --- llvm/test/Transforms/InstCombine/or.ll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll index aeb42744b6838..5b88b1c692482 100644 --- a/llvm/test/Transforms/InstCombine/or.ll +++ b/llvm/test/Transforms/InstCombine/or.ll @@ -2129,7 +2129,7 @@ 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 +; 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 From d6eecb3cd65dedfe62f51dae16eda1baa92ba4d6 Mon Sep 17 00:00:00 2001 From: Wenju He Date: Fri, 31 Oct 2025 08:33:15 +0100 Subject: [PATCH 12/12] use m_SMax --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 4 ++-- llvm/test/Transforms/InstCombine/or.ll | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 952219a1d55cc..cbaff294819a2 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -4003,8 +4003,8 @@ static Value *FoldOrOfSelectSmaxToAbs(BinaryOperator &I, InstCombiner::BuilderTy &Builder) { Value *X; Value *Sel; - if (match(&I, m_c_Or(m_Value(Sel), m_OneUse(m_Intrinsic( - m_Value(X), m_ZeroInt()))))) { + if (match(&I, + m_c_Or(m_Value(Sel), m_OneUse(m_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()), diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll index 5b88b1c692482..f61a1970d3aa4 100644 --- a/llvm/test/Transforms/InstCombine/or.ll +++ b/llvm/test/Transforms/InstCombine/or.ll @@ -2143,7 +2143,7 @@ define i8 @or_select_smax_neg_to_abs(i8 %a){ ret i8 %sel } -; TODO Fold to abs https://alive2.llvm.org/ce/z/DybfHG +; 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:%.*]]