Skip to content

Commit dedc58d

Browse files
committed
[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.
1 parent 625e666 commit dedc58d

File tree

2 files changed

+42
-12
lines changed

2 files changed

+42
-12
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,19 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
15201520
return BinaryOperator::CreateSub(B, Shl);
15211521
}
15221522

1523+
// Canonicalize signum variant that ends in add:
1524+
// (A s>> (BW - 1)) + (zext (A s> 0)) --> (A s>> (BW - 1)) | (zext (A != 0))
1525+
ICmpInst::Predicate Pred;
1526+
uint64_t BitWidth = Ty->getScalarSizeInBits();
1527+
if (match(LHS, m_AShr(m_Value(A), m_SpecificIntAllowUndef(BitWidth - 1))) &&
1528+
match(RHS, m_OneUse(m_ZExt(
1529+
m_OneUse(m_ICmp(Pred, m_Specific(A), m_ZeroInt()))))) &&
1530+
Pred == CmpInst::ICMP_SGT) {
1531+
Value *NotZero = Builder.CreateIsNotNull(A, "isnotnull");
1532+
Value *Zext = Builder.CreateZExt(NotZero, Ty, "isnotnull.zext");
1533+
return BinaryOperator::CreateOr(LHS, Zext);
1534+
}
1535+
15231536
if (Instruction *Ashr = foldAddToAshr(I))
15241537
return Ashr;
15251538

llvm/test/Transforms/InstCombine/add.ll

+29-12
Original file line numberDiff line numberDiff line change
@@ -2731,12 +2731,14 @@ define i32 @floor_sdiv_wrong_op(i32 %x, i32 %y) {
27312731
ret i32 %r
27322732
}
27332733

2734+
; (X s>> (BW - 1)) + (zext (X s> 0)) --> (X s>> (BW - 1)) | (zext (X != 0))
2735+
27342736
define i8 @signum_i8_i8(i8 %x) {
27352737
; CHECK-LABEL: @signum_i8_i8(
2736-
; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], 0
2737-
; CHECK-NEXT: [[ZGT0:%.*]] = zext i1 [[SGT0]] to i8
2738-
; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i8 [[X]], 7
2739-
; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[SIGNBIT]], [[ZGT0]]
2738+
; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i8 [[X:%.*]], 7
2739+
; CHECK-NEXT: [[ISNOTNULL:%.*]] = icmp ne i8 [[X]], 0
2740+
; CHECK-NEXT: [[ISNOTNULL_ZEXT:%.*]] = zext i1 [[ISNOTNULL]] to i8
2741+
; CHECK-NEXT: [[R:%.*]] = or i8 [[SIGNBIT]], [[ISNOTNULL_ZEXT]]
27402742
; CHECK-NEXT: ret i8 [[R]]
27412743
;
27422744
%sgt0 = icmp sgt i8 %x, 0
@@ -2746,13 +2748,15 @@ define i8 @signum_i8_i8(i8 %x) {
27462748
ret i8 %r
27472749
}
27482750

2751+
; extra use of shift is ok
2752+
27492753
define i8 @signum_i8_i8_use1(i8 %x) {
27502754
; CHECK-LABEL: @signum_i8_i8_use1(
2751-
; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], 0
2752-
; CHECK-NEXT: [[ZGT0:%.*]] = zext i1 [[SGT0]] to i8
2753-
; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i8 [[X]], 7
2755+
; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr i8 [[X:%.*]], 7
27542756
; CHECK-NEXT: call void @use(i8 [[SIGNBIT]])
2755-
; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[SIGNBIT]], [[ZGT0]]
2757+
; CHECK-NEXT: [[ISNOTNULL:%.*]] = icmp ne i8 [[X]], 0
2758+
; CHECK-NEXT: [[ISNOTNULL_ZEXT:%.*]] = zext i1 [[ISNOTNULL]] to i8
2759+
; CHECK-NEXT: [[R:%.*]] = or i8 [[SIGNBIT]], [[ISNOTNULL_ZEXT]]
27562760
; CHECK-NEXT: ret i8 [[R]]
27572761
;
27582762
%sgt0 = icmp sgt i8 %x, 0
@@ -2763,6 +2767,8 @@ define i8 @signum_i8_i8_use1(i8 %x) {
27632767
ret i8 %r
27642768
}
27652769

2770+
; negative test
2771+
27662772
define i8 @signum_i8_i8_use2(i8 %x) {
27672773
; CHECK-LABEL: @signum_i8_i8_use2(
27682774
; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], 0
@@ -2780,6 +2786,8 @@ define i8 @signum_i8_i8_use2(i8 %x) {
27802786
ret i8 %r
27812787
}
27822788

2789+
; negative test
2790+
27832791
define i8 @signum_i8_i8_use3(i8 %x) {
27842792
; CHECK-LABEL: @signum_i8_i8_use3(
27852793
; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], 0
@@ -2797,12 +2805,15 @@ define i8 @signum_i8_i8_use3(i8 %x) {
27972805
ret i8 %r
27982806
}
27992807

2808+
; poison/undef is ok to propagate in shift amount
2809+
; complexity canonicalization guarantees that shift is op0 of add
2810+
28002811
define <2 x i5> @signum_v2i5_v2i5(<2 x i5> %x) {
28012812
; CHECK-LABEL: @signum_v2i5_v2i5(
2802-
; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt <2 x i5> [[X:%.*]], zeroinitializer
2803-
; CHECK-NEXT: [[ZGT0:%.*]] = zext <2 x i1> [[SGT0]] to <2 x i5>
2804-
; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr <2 x i5> [[X]], <i5 4, i5 poison>
2805-
; CHECK-NEXT: [[R:%.*]] = add <2 x i5> [[SIGNBIT]], [[ZGT0]]
2813+
; CHECK-NEXT: [[SIGNBIT:%.*]] = ashr <2 x i5> [[X:%.*]], <i5 4, i5 poison>
2814+
; CHECK-NEXT: [[ISNOTNULL:%.*]] = icmp ne <2 x i5> [[X]], zeroinitializer
2815+
; CHECK-NEXT: [[ISNOTNULL_ZEXT:%.*]] = zext <2 x i1> [[ISNOTNULL]] to <2 x i5>
2816+
; CHECK-NEXT: [[R:%.*]] = or <2 x i5> [[SIGNBIT]], [[ISNOTNULL_ZEXT]]
28062817
; CHECK-NEXT: ret <2 x i5> [[R]]
28072818
;
28082819
%sgt0 = icmp sgt <2 x i5> %x, zeroinitializer
@@ -2812,6 +2823,8 @@ define <2 x i5> @signum_v2i5_v2i5(<2 x i5> %x) {
28122823
ret <2 x i5> %r
28132824
}
28142825

2826+
; negative test
2827+
28152828
define i8 @signum_i8_i8_wrong_sh_amt(i8 %x) {
28162829
; CHECK-LABEL: @signum_i8_i8_wrong_sh_amt(
28172830
; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], 0
@@ -2827,6 +2840,8 @@ define i8 @signum_i8_i8_wrong_sh_amt(i8 %x) {
28272840
ret i8 %r
28282841
}
28292842

2843+
; negative test
2844+
28302845
define i8 @signum_i8_i8_wrong_ext(i8 %x) {
28312846
; CHECK-LABEL: @signum_i8_i8_wrong_ext(
28322847
; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], 0
@@ -2842,6 +2857,8 @@ define i8 @signum_i8_i8_wrong_ext(i8 %x) {
28422857
ret i8 %r
28432858
}
28442859

2860+
; negative test
2861+
28452862
define i8 @signum_i8_i8_wrong_pred(i8 %x) {
28462863
; CHECK-LABEL: @signum_i8_i8_wrong_pred(
28472864
; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[X:%.*]], -1

0 commit comments

Comments
 (0)