[llvm] 2f217c1 - [InstCombine] Canonicalize ((X & -X) - 1) --> ((X - 1) & ~X) (PR51784)
Simon Pilgrim via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 24 08:51:07 PDT 2022
Author: Simon Pilgrim
Date: 2022-08-24T16:50:43+01:00
New Revision: 2f217c12142639900a0d25c5d9ce67142f7bd840
URL: https://github.com/llvm/llvm-project/commit/2f217c12142639900a0d25c5d9ce67142f7bd840
DIFF: https://github.com/llvm/llvm-project/commit/2f217c12142639900a0d25c5d9ce67142f7bd840.diff
LOG: [InstCombine] Canonicalize ((X & -X) - 1) --> ((X - 1) & ~X) (PR51784)
Enables the ctpop((x & -x ) - 1) -> cttz(x, false) fold
Alive2: https://alive2.llvm.org/ce/z/EDk4h7 (((X & -X) - 1) --> (~X & (X - 1)) )
Alive2: https://alive2.llvm.org/ce/z/8Yr3XG (CTPOP -> CTTZ)
Fixes #51126
Differential Revision: https://reviews.llvm.org/D110488
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
llvm/test/Transforms/InstCombine/add-mask-neg.ll
llvm/test/Transforms/InstCombine/ctpop-cttz.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 94f21dd3c6cc..8dfe72e36b72 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1415,6 +1415,17 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
return &I;
}
+ // Canonicalize ((A & -A) - 1) --> ((A - 1) & ~A)
+ // Forms all commutable operations, and simplifies ctpop -> cttz folds.
+ if (match(&I,
+ m_Add(m_OneUse(m_c_And(m_Value(A), m_OneUse(m_Neg(m_Deferred(A))))),
+ m_AllOnes()))) {
+ Constant *AllOnes = ConstantInt::getAllOnesValue(RHS->getType());
+ Value *Dec = Builder.CreateAdd(A, AllOnes);
+ Value *Not = Builder.CreateXor(A, AllOnes);
+ return BinaryOperator::CreateAnd(Dec, Not);
+ }
+
// TODO(jingyue): Consider willNotOverflowSignedAdd and
// willNotOverflowUnsignedAdd to reduce the number of invocations of
// computeKnownBits.
diff --git a/llvm/test/Transforms/InstCombine/add-mask-neg.ll b/llvm/test/Transforms/InstCombine/add-mask-neg.ll
index 0fe1b743d7fd..5fad6155d348 100644
--- a/llvm/test/Transforms/InstCombine/add-mask-neg.ll
+++ b/llvm/test/Transforms/InstCombine/add-mask-neg.ll
@@ -2,14 +2,14 @@
; RUN: opt < %s -S -passes=instcombine | FileCheck %s
;
-; TODO: Canonicalize ((X & -X) - 1) --> (~X & (X - 1))
+; Canonicalize ((X & -X) - 1) --> ((X - 1) & ~X)
;
define i32 @dec_mask_neg_i32(i32 %X) {
; CHECK-LABEL: @dec_mask_neg_i32(
-; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]]
-; CHECK-NEXT: [[MASK:%.*]] = and i32 [[NEG]], [[X]]
-; CHECK-NEXT: [[DEC:%.*]] = add i32 [[MASK]], -1
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -1
+; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[X]], -1
+; CHECK-NEXT: [[DEC:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i32 [[DEC]]
;
%neg = sub i32 0, %X
@@ -21,9 +21,9 @@ define i32 @dec_mask_neg_i32(i32 %X) {
define i32 @dec_mask_commute_neg_i32(i32 %A) {
; CHECK-LABEL: @dec_mask_commute_neg_i32(
; CHECK-NEXT: [[X:%.*]] = sdiv i32 42, [[A:%.*]]
-; CHECK-NEXT: [[NEG:%.*]] = sub nsw i32 0, [[X]]
-; CHECK-NEXT: [[MASK:%.*]] = and i32 [[X]], [[NEG]]
-; CHECK-NEXT: [[DEC:%.*]] = add i32 [[MASK]], -1
+; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[X]], -1
+; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[X]], -1
+; CHECK-NEXT: [[DEC:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i32 [[DEC]]
;
%X = sdiv i32 42, %A ; thwart complexity-based canonicalization
@@ -35,9 +35,9 @@ define i32 @dec_mask_commute_neg_i32(i32 %A) {
define i32 @dec_commute_mask_neg_i32(i32 %X) {
; CHECK-LABEL: @dec_commute_mask_neg_i32(
-; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]]
-; CHECK-NEXT: [[MASK:%.*]] = and i32 [[NEG]], [[X]]
-; CHECK-NEXT: [[DEC:%.*]] = add i32 [[MASK]], -1
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -1
+; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[X]], -1
+; CHECK-NEXT: [[DEC:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i32 [[DEC]]
;
%neg = sub i32 0, %X
@@ -78,9 +78,9 @@ define i32 @dec_mask_multiuse_neg_i32(i32 %X) {
define <2 x i32> @dec_mask_neg_v2i32(<2 x i32> %X) {
; CHECK-LABEL: @dec_mask_neg_v2i32(
-; CHECK-NEXT: [[NEG:%.*]] = sub <2 x i32> zeroinitializer, [[X:%.*]]
-; CHECK-NEXT: [[MASK:%.*]] = and <2 x i32> [[NEG]], [[X]]
-; CHECK-NEXT: [[DEC:%.*]] = add <2 x i32> [[MASK]], <i32 -1, i32 -1>
+; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], <i32 -1, i32 -1>
+; CHECK-NEXT: [[TMP2:%.*]] = xor <2 x i32> [[X]], <i32 -1, i32 -1>
+; CHECK-NEXT: [[DEC:%.*]] = and <2 x i32> [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret <2 x i32> [[DEC]]
;
%neg = sub <2 x i32> zeroinitializer, %X
@@ -91,9 +91,9 @@ define <2 x i32> @dec_mask_neg_v2i32(<2 x i32> %X) {
define <2 x i32> @dec_mask_neg_v2i32_undef(<2 x i32> %X) {
; CHECK-LABEL: @dec_mask_neg_v2i32_undef(
-; CHECK-NEXT: [[NEG:%.*]] = sub <2 x i32> zeroinitializer, [[X:%.*]]
-; CHECK-NEXT: [[MASK:%.*]] = and <2 x i32> [[NEG]], [[X]]
-; CHECK-NEXT: [[DEC:%.*]] = add <2 x i32> [[MASK]], <i32 -1, i32 undef>
+; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], <i32 -1, i32 -1>
+; CHECK-NEXT: [[TMP2:%.*]] = xor <2 x i32> [[X]], <i32 -1, i32 -1>
+; CHECK-NEXT: [[DEC:%.*]] = and <2 x i32> [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret <2 x i32> [[DEC]]
;
%neg = sub <2 x i32> zeroinitializer, %X
diff --git a/llvm/test/Transforms/InstCombine/ctpop-cttz.ll b/llvm/test/Transforms/InstCombine/ctpop-cttz.ll
index 84af8b37a7a6..ae3f1d49d762 100644
--- a/llvm/test/Transforms/InstCombine/ctpop-cttz.ll
+++ b/llvm/test/Transforms/InstCombine/ctpop-cttz.ll
@@ -94,11 +94,8 @@ define i32 @ctpop2_multiuse(i32 %0) {
; __builtin_popcount((i & -i) - 1) -> __builtin_cttz(i, false)
define i32 @ctpop3(i32 %0) {
; CHECK-LABEL: @ctpop3(
-; CHECK-NEXT: [[TMP2:%.*]] = sub i32 0, [[TMP0:%.*]]
-; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], [[TMP0]]
-; CHECK-NEXT: [[TMP4:%.*]] = add i32 [[TMP3]], -1
-; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[TMP4]]), !range [[RNG0]]
-; CHECK-NEXT: ret i32 [[TMP5]]
+; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.cttz.i32(i32 [[TMP0:%.*]], i1 false), !range [[RNG0]]
+; CHECK-NEXT: ret i32 [[TMP2]]
;
%2 = sub i32 0, %0
%3 = and i32 %2, %0
@@ -109,11 +106,8 @@ define i32 @ctpop3(i32 %0) {
define <2 x i32> @ctpop3v(<2 x i32> %0) {
; CHECK-LABEL: @ctpop3v(
-; CHECK-NEXT: [[TMP2:%.*]] = sub <2 x i32> zeroinitializer, [[TMP0:%.*]]
-; CHECK-NEXT: [[TMP3:%.*]] = and <2 x i32> [[TMP2]], [[TMP0]]
-; CHECK-NEXT: [[TMP4:%.*]] = add <2 x i32> [[TMP3]], <i32 -1, i32 -1>
-; CHECK-NEXT: [[TMP5:%.*]] = tail call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> [[TMP4]])
-; CHECK-NEXT: ret <2 x i32> [[TMP5]]
+; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[TMP0:%.*]], i1 false)
+; CHECK-NEXT: ret <2 x i32> [[TMP2]]
;
%2 = sub <2 x i32> zeroinitializer, %0
%3 = and <2 x i32> %2, %0
@@ -124,11 +118,8 @@ define <2 x i32> @ctpop3v(<2 x i32> %0) {
define <2 x i32> @ctpop3v_undef(<2 x i32> %0) {
; CHECK-LABEL: @ctpop3v_undef(
-; CHECK-NEXT: [[TMP2:%.*]] = sub <2 x i32> zeroinitializer, [[TMP0:%.*]]
-; CHECK-NEXT: [[TMP3:%.*]] = and <2 x i32> [[TMP2]], [[TMP0]]
-; CHECK-NEXT: [[TMP4:%.*]] = add <2 x i32> [[TMP3]], <i32 -1, i32 undef>
-; CHECK-NEXT: [[TMP5:%.*]] = tail call <2 x i32> @llvm.ctpop.v2i32(<2 x i32> [[TMP4]])
-; CHECK-NEXT: ret <2 x i32> [[TMP5]]
+; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[TMP0:%.*]], i1 false)
+; CHECK-NEXT: ret <2 x i32> [[TMP2]]
;
%2 = sub <2 x i32> zeroinitializer, %0
%3 = and <2 x i32> %2, %0
More information about the llvm-commits
mailing list