[llvm] dedc58d - [InstCombine] canonicalize a signum (spaceship) that ends in add
Sanjay Patel via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 16 09:58:41 PST 2023
Author: Sanjay Patel
Date: 2023-01-16T12:47:21-05:00
New Revision: dedc58da49c7a9d059cc4364ce737f6c7dc15569
URL: https://github.com/llvm/llvm-project/commit/dedc58da49c7a9d059cc4364ce737f6c7dc15569
DIFF: https://github.com/llvm/llvm-project/commit/dedc58da49c7a9d059cc4364ce737f6c7dc15569.diff
LOG: [InstCombine] canonicalize a signum (spaceship) that ends in add
(A s>> (BW - 1)) + (zext (A s> 0)) --> (A s>> (BW - 1)) | (zext (A != 0))
https://alive2.llvm.org/ce/z/V-nM8N
This is not the form that we currently match as m_Signum(),
but I'm not sure if one is better than the other, so there's
a follow-up patch needed either way.
For this patch, it should be better for analysis to use a
not-null test and bitwise logic rather than >0 with add.
Codegen doesn't seem significantly different on any targets
that I looked at.
Also note that none of these variants is shown in issue #60012 -
those generally include at least one 'select', so that's likely
where these patterns will end up.
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
llvm/test/Transforms/InstCombine/add.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index e650be1fec9f4..21bb916523694 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1520,6 +1520,19 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
return BinaryOperator::CreateSub(B, Shl);
}
+ // Canonicalize signum variant that ends in add:
+ // (A s>> (BW - 1)) + (zext (A s> 0)) --> (A s>> (BW - 1)) | (zext (A != 0))
+ ICmpInst::Predicate Pred;
+ uint64_t BitWidth = Ty->getScalarSizeInBits();
+ if (match(LHS, m_AShr(m_Value(A), m_SpecificIntAllowUndef(BitWidth - 1))) &&
+ match(RHS, m_OneUse(m_ZExt(
+ m_OneUse(m_ICmp(Pred, m_Specific(A), m_ZeroInt()))))) &&
+ Pred == CmpInst::ICMP_SGT) {
+ Value *NotZero = Builder.CreateIsNotNull(A, "isnotnull");
+ Value *Zext = Builder.CreateZExt(NotZero, Ty, "isnotnull.zext");
+ return BinaryOperator::CreateOr(LHS, Zext);
+ }
+
if (Instruction *Ashr = foldAddToAshr(I))
return Ashr;
diff --git a/llvm/test/Transforms/InstCombine/add.ll b/llvm/test/Transforms/InstCombine/add.ll
index 73e21d4370b7e..21adfdf3c8074 100644
--- a/llvm/test/Transforms/InstCombine/add.ll
+++ b/llvm/test/Transforms/InstCombine/add.ll
@@ -2731,12 +2731,14 @@ define i32 @floor_sdiv_wrong_op(i32 %x, i32 %y) {
ret i32 %r
}
+; (X s>> (BW - 1)) + (zext (X s> 0)) --> (X s>> (BW - 1)) | (zext (X != 0))
+
define i8 @signum_i8_i8(i8 %x) {
; CHECK-LABEL: @signum_i8_i8(
-; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], 0
-; CHECK-NEXT: [[ZGT0:%.*]] = zext i1 [[SGT0]] to i8
-; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i8 [[X]], 7
-; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[SIGNBIT]], [[ZGT0]]
+; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i8 [[X:%.*]], 7
+; CHECK-NEXT: [[ISNOTNULL:%.*]] = icmp ne i8 [[X]], 0
+; CHECK-NEXT: [[ISNOTNULL_ZEXT:%.*]] = zext i1 [[ISNOTNULL]] to i8
+; CHECK-NEXT: [[R:%.*]] = or i8 [[SIGNBIT]], [[ISNOTNULL_ZEXT]]
; CHECK-NEXT: ret i8 [[R]]
;
%sgt0 = icmp sgt i8 %x, 0
@@ -2746,13 +2748,15 @@ define i8 @signum_i8_i8(i8 %x) {
ret i8 %r
}
+; extra use of shift is ok
+
define i8 @signum_i8_i8_use1(i8 %x) {
; CHECK-LABEL: @signum_i8_i8_use1(
-; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], 0
-; CHECK-NEXT: [[ZGT0:%.*]] = zext i1 [[SGT0]] to i8
-; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i8 [[X]], 7
+; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i8 [[X:%.*]], 7
; CHECK-NEXT: call void @use(i8 [[SIGNBIT]])
-; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[SIGNBIT]], [[ZGT0]]
+; CHECK-NEXT: [[ISNOTNULL:%.*]] = icmp ne i8 [[X]], 0
+; CHECK-NEXT: [[ISNOTNULL_ZEXT:%.*]] = zext i1 [[ISNOTNULL]] to i8
+; CHECK-NEXT: [[R:%.*]] = or i8 [[SIGNBIT]], [[ISNOTNULL_ZEXT]]
; CHECK-NEXT: ret i8 [[R]]
;
%sgt0 = icmp sgt i8 %x, 0
@@ -2763,6 +2767,8 @@ define i8 @signum_i8_i8_use1(i8 %x) {
ret i8 %r
}
+; negative test
+
define i8 @signum_i8_i8_use2(i8 %x) {
; CHECK-LABEL: @signum_i8_i8_use2(
; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], 0
@@ -2780,6 +2786,8 @@ define i8 @signum_i8_i8_use2(i8 %x) {
ret i8 %r
}
+; negative test
+
define i8 @signum_i8_i8_use3(i8 %x) {
; CHECK-LABEL: @signum_i8_i8_use3(
; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], 0
@@ -2797,12 +2805,15 @@ define i8 @signum_i8_i8_use3(i8 %x) {
ret i8 %r
}
+; poison/undef is ok to propagate in shift amount
+; complexity canonicalization guarantees that shift is op0 of add
+
define <2 x i5> @signum_v2i5_v2i5(<2 x i5> %x) {
; CHECK-LABEL: @signum_v2i5_v2i5(
-; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt <2 x i5> [[X:%.*]], zeroinitializer
-; CHECK-NEXT: [[ZGT0:%.*]] = zext <2 x i1> [[SGT0]] to <2 x i5>
-; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr <2 x i5> [[X]], <i5 4, i5 poison>
-; CHECK-NEXT: [[R:%.*]] = add <2 x i5> [[SIGNBIT]], [[ZGT0]]
+; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr <2 x i5> [[X:%.*]], <i5 4, i5 poison>
+; CHECK-NEXT: [[ISNOTNULL:%.*]] = icmp ne <2 x i5> [[X]], zeroinitializer
+; CHECK-NEXT: [[ISNOTNULL_ZEXT:%.*]] = zext <2 x i1> [[ISNOTNULL]] to <2 x i5>
+; CHECK-NEXT: [[R:%.*]] = or <2 x i5> [[SIGNBIT]], [[ISNOTNULL_ZEXT]]
; CHECK-NEXT: ret <2 x i5> [[R]]
;
%sgt0 = icmp sgt <2 x i5> %x, zeroinitializer
@@ -2812,6 +2823,8 @@ define <2 x i5> @signum_v2i5_v2i5(<2 x i5> %x) {
ret <2 x i5> %r
}
+; negative test
+
define i8 @signum_i8_i8_wrong_sh_amt(i8 %x) {
; CHECK-LABEL: @signum_i8_i8_wrong_sh_amt(
; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], 0
@@ -2827,6 +2840,8 @@ define i8 @signum_i8_i8_wrong_sh_amt(i8 %x) {
ret i8 %r
}
+; negative test
+
define i8 @signum_i8_i8_wrong_ext(i8 %x) {
; CHECK-LABEL: @signum_i8_i8_wrong_ext(
; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], 0
@@ -2842,6 +2857,8 @@ define i8 @signum_i8_i8_wrong_ext(i8 %x) {
ret i8 %r
}
+; negative test
+
define i8 @signum_i8_i8_wrong_pred(i8 %x) {
; CHECK-LABEL: @signum_i8_i8_wrong_pred(
; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], -1
More information about the llvm-commits
mailing list