[llvm] 4220ef2 - [InstCombine] Add fold for redundant sign bits count comparison
Alexander Shaposhnikov via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 30 02:07:13 PDT 2022
Author: Alexander Shaposhnikov
Date: 2022-07-30T09:06:53Z
New Revision: 4220ef2be1c911f92b48a895fdd18e4077b322f5
URL: https://github.com/llvm/llvm-project/commit/4220ef2be1c911f92b48a895fdd18e4077b322f5
DIFF: https://github.com/llvm/llvm-project/commit/4220ef2be1c911f92b48a895fdd18e4077b322f5.diff
LOG: [InstCombine] Add fold for redundant sign bits count comparison
For power-of-2 C:
((X s>> ShiftC) ^ X) u< C --> (X + C) u< (C << 1)
((X s>> ShiftC) ^ X) u> (C - 1) --> (X + C) u> ((C << 1) - 1)
(https://github.com/llvm/llvm-project/issues/56479)
Test plan:
0/ ninja check-llvm check-clang + bootstrap LLVM/Clang
1/ https://alive2.llvm.org/ce/z/eEUfx3
Differential revision: https://reviews.llvm.org/D130433
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
llvm/lib/Transforms/InstCombine/InstCombineInternal.h
llvm/test/Transforms/InstCombine/icmp.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index fc3b115e09bd..4ac04fb826fc 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -1597,6 +1597,9 @@ Instruction *InstCombinerImpl::foldICmpTruncConstant(ICmpInst &Cmp,
Instruction *InstCombinerImpl::foldICmpXorConstant(ICmpInst &Cmp,
BinaryOperator *Xor,
const APInt &C) {
+ if (Instruction *I = foldICmpXorShiftConst(Cmp, Xor, C))
+ return I;
+
Value *X = Xor->getOperand(0);
Value *Y = Xor->getOperand(1);
const APInt *XorC;
@@ -1660,6 +1663,37 @@ Instruction *InstCombinerImpl::foldICmpXorConstant(ICmpInst &Cmp,
return nullptr;
}
+/// For power-of-2 C:
+/// ((X s>> ShiftC) ^ X) u< C --> (X + C) u< (C << 1)
+/// ((X s>> ShiftC) ^ X) u> (C - 1) --> (X + C) u> ((C << 1) - 1)
+Instruction *InstCombinerImpl::foldICmpXorShiftConst(ICmpInst &Cmp,
+ BinaryOperator *Xor,
+ const APInt &C) {
+ CmpInst::Predicate Pred = Cmp.getPredicate();
+ APInt PowerOf2;
+ if (Pred == ICmpInst::ICMP_ULT)
+ PowerOf2 = C;
+ else if (Pred == ICmpInst::ICMP_UGT && !C.isMaxValue())
+ PowerOf2 = C + 1;
+ else
+ return nullptr;
+ if (!PowerOf2.isPowerOf2())
+ return nullptr;
+ Value *X;
+ const APInt *ShiftC;
+ if (!match(Xor, m_OneUse(m_c_Xor(m_Value(X),
+ m_AShr(m_Deferred(X), m_APInt(ShiftC))))))
+ return nullptr;
+ uint64_t Shift = ShiftC->getLimitedValue();
+ Type *XType = X->getType();
+ if (Shift == 0 || PowerOf2.isMinSignedValue())
+ return nullptr;
+ Value *Add = Builder.CreateAdd(X, ConstantInt::get(XType, PowerOf2));
+ APInt Bound =
+ Pred == ICmpInst::ICMP_ULT ? PowerOf2 << 1 : ((PowerOf2 << 1) - 1);
+ return new ICmpInst(Pred, Add, ConstantInt::get(XType, Bound));
+}
+
/// Fold icmp (and (sh X, Y), C2), C1.
Instruction *InstCombinerImpl::foldICmpAndShift(ICmpInst &Cmp,
BinaryOperator *And,
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 664226ec187b..cb533908e3fe 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -716,6 +716,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
const APInt &C1);
Instruction *foldICmpAndShift(ICmpInst &Cmp, BinaryOperator *And,
const APInt &C1, const APInt &C2);
+ Instruction *foldICmpXorShiftConst(ICmpInst &Cmp, BinaryOperator *Xor,
+ const APInt &C);
Instruction *foldICmpShrConstConst(ICmpInst &I, Value *ShAmt, const APInt &C1,
const APInt &C2);
Instruction *foldICmpShlConstConst(ICmpInst &I, Value *ShAmt, const APInt &C1,
diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll
index ef8da2ff6fb0..1cfbeb6ed1d3 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -4113,9 +4113,8 @@ define i1 @signbit_true_logic_uses_commute(i64 %x) {
define i1 @redundant_sign_bit_count_ult_1_2(i32 %x) {
; CHECK-LABEL: @redundant_sign_bit_count_ult_1_2(
-; CHECK-NEXT: [[Y:%.*]] = ashr i32 [[X:%.*]], 1
-; CHECK-NEXT: [[Z:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[Z]], 4
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 4
+; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[TMP1]], 8
; CHECK-NEXT: ret i1 [[C]]
;
%y = ashr i32 %x, 1
@@ -4126,9 +4125,8 @@ define i1 @redundant_sign_bit_count_ult_1_2(i32 %x) {
define i1 @redundant_sign_bit_count_ult_1_30(i32 %x) {
; CHECK-LABEL: @redundant_sign_bit_count_ult_1_30(
-; CHECK-NEXT: [[Y:%.*]] = ashr i32 [[X:%.*]], 1
-; CHECK-NEXT: [[Z:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[Z]], 1073741824
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 1073741824
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[TMP1]], -1
; CHECK-NEXT: ret i1 [[C]]
;
%y = ashr i32 %x, 1
@@ -4139,9 +4137,8 @@ define i1 @redundant_sign_bit_count_ult_1_30(i32 %x) {
define i1 @redundant_sign_bit_count_ult_31_2(i32 %x) {
; CHECK-LABEL: @redundant_sign_bit_count_ult_31_2(
-; CHECK-NEXT: [[Y:%.*]] = ashr i32 [[X:%.*]], 31
-; CHECK-NEXT: [[Z:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[Z]], 4
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 4
+; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[TMP1]], 8
; CHECK-NEXT: ret i1 [[C]]
;
%y = ashr i32 %x, 31
@@ -4152,9 +4149,8 @@ define i1 @redundant_sign_bit_count_ult_31_2(i32 %x) {
define i1 @redundant_sign_bit_count_ult_31_30(i32 %x) {
; CHECK-LABEL: @redundant_sign_bit_count_ult_31_30(
-; CHECK-NEXT: [[Y:%.*]] = ashr i32 [[X:%.*]], 31
-; CHECK-NEXT: [[Z:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[Z]], 1073741824
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 1073741824
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[TMP1]], -1
; CHECK-NEXT: ret i1 [[C]]
;
%y = ashr i32 %x, 31
@@ -4169,8 +4165,8 @@ define i1 @redundant_sign_bit_count_ult_31_30_extra_use_ashr(i32 %x) {
; CHECK-LABEL: @redundant_sign_bit_count_ult_31_30_extra_use_ashr(
; CHECK-NEXT: [[Y:%.*]] = ashr i32 [[X:%.*]], 31
; CHECK-NEXT: call void @use_i32(i32 [[Y]])
-; CHECK-NEXT: [[Z:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[Z]], 1073741824
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], 1073741824
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[TMP1]], -1
; CHECK-NEXT: ret i1 [[C]]
;
%y = ashr i32 %x, 31
@@ -4224,9 +4220,8 @@ define i1 @wrong_shift_opcode_i8(i8 %x) {
define i1 @redundant_sign_bit_count_ult_31_30_commute(i32 %xsrc) {
; CHECK-LABEL: @redundant_sign_bit_count_ult_31_30_commute(
; CHECK-NEXT: [[X:%.*]] = mul i32 [[XSRC:%.*]], 13
-; CHECK-NEXT: [[Y:%.*]] = ashr i32 [[X]], 31
-; CHECK-NEXT: [[Z:%.*]] = xor i32 [[X]], [[Y]]
-; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[Z]], 1073741824
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], 1073741824
+; CHECK-NEXT: [[C:%.*]] = icmp sgt i32 [[TMP1]], -1
; CHECK-NEXT: ret i1 [[C]]
;
%x = mul i32 %xsrc, 13 ; thwart complexity-based canonicalization
@@ -4238,9 +4233,8 @@ define i1 @redundant_sign_bit_count_ult_31_30_commute(i32 %xsrc) {
define i1 @redundant_sign_bit_count_i8(i8 %x) {
; CHECK-LABEL: @redundant_sign_bit_count_i8(
-; CHECK-NEXT: [[Y:%.*]] = ashr i8 [[X:%.*]], 5
-; CHECK-NEXT: [[Z:%.*]] = xor i8 [[Y]], [[X]]
-; CHECK-NEXT: [[C:%.*]] = icmp ult i8 [[Z]], 2
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], 2
+; CHECK-NEXT: [[C:%.*]] = icmp ult i8 [[TMP1]], 4
; CHECK-NEXT: ret i1 [[C]]
;
%y = ashr i8 %x, 5
@@ -4252,9 +4246,8 @@ define i1 @redundant_sign_bit_count_i8(i8 %x) {
define <2 x i1> @redundant_sign_bit_count_ult_31_30_vector(<2 x i32> %xsrc) {
; CHECK-LABEL: @redundant_sign_bit_count_ult_31_30_vector(
; CHECK-NEXT: [[X:%.*]] = mul <2 x i32> [[XSRC:%.*]], <i32 13, i32 13>
-; CHECK-NEXT: [[Y:%.*]] = ashr <2 x i32> [[X]], <i32 31, i32 31>
-; CHECK-NEXT: [[Z:%.*]] = xor <2 x i32> [[X]], [[Y]]
-; CHECK-NEXT: [[C:%.*]] = icmp ult <2 x i32> [[Z]], <i32 1073741824, i32 1073741824>
+; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[X]], <i32 1073741824, i32 1073741824>
+; CHECK-NEXT: [[C:%.*]] = icmp sgt <2 x i32> [[TMP1]], <i32 -1, i32 -1>
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%x = mul <2 x i32> %xsrc, <i32 13, i32 13> ; thwart complexity-based canonicalization
@@ -4266,9 +4259,8 @@ define <2 x i1> @redundant_sign_bit_count_ult_31_30_vector(<2 x i32> %xsrc) {
define i1 @redundant_sign_bit_count_ugt_1_2(i32 %x) {
; CHECK-LABEL: @redundant_sign_bit_count_ugt_1_2(
-; CHECK-NEXT: [[Y:%.*]] = ashr i32 [[X:%.*]], 1
-; CHECK-NEXT: [[Z:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[Z]], 3
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -4
+; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[TMP1]], -8
; CHECK-NEXT: ret i1 [[C]]
;
%y = ashr i32 %x, 1
@@ -4279,9 +4271,8 @@ define i1 @redundant_sign_bit_count_ugt_1_2(i32 %x) {
define i1 @redundant_sign_bit_count_ugt_1_30(i32 %x) {
; CHECK-LABEL: @redundant_sign_bit_count_ugt_1_30(
-; CHECK-NEXT: [[Y:%.*]] = ashr i32 [[X:%.*]], 1
-; CHECK-NEXT: [[Z:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[Z]], 1073741823
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 1073741824
+; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[C]]
;
%y = ashr i32 %x, 1
@@ -4292,9 +4283,8 @@ define i1 @redundant_sign_bit_count_ugt_1_30(i32 %x) {
define i1 @redundant_sign_bit_count_ugt_31_2(i32 %x) {
; CHECK-LABEL: @redundant_sign_bit_count_ugt_31_2(
-; CHECK-NEXT: [[Y:%.*]] = ashr i32 [[X:%.*]], 31
-; CHECK-NEXT: [[Z:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[Z]], 3
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -4
+; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[TMP1]], -8
; CHECK-NEXT: ret i1 [[C]]
;
%y = ashr i32 %x, 31
@@ -4305,9 +4295,8 @@ define i1 @redundant_sign_bit_count_ugt_31_2(i32 %x) {
define i1 @redundant_sign_bit_count_ugt_31_30(i32 %x) {
; CHECK-LABEL: @redundant_sign_bit_count_ugt_31_30(
-; CHECK-NEXT: [[Y:%.*]] = ashr i32 [[X:%.*]], 31
-; CHECK-NEXT: [[Z:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[Z]], 1073741823
+; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 1073741824
+; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[C]]
;
%y = ashr i32 %x, 31
More information about the llvm-commits
mailing list