[llvm] 3a696f6 - [InstCombine] rotate(X,Z) eq/ne rotate(Y,Z) ---> X eq/ne Y (PR51565)
Dávid Bolvanský via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 4 09:58:51 PDT 2021
Author: Dávid Bolvanský
Date: 2021-09-04T18:58:44+02:00
New Revision: 3a696f6092effe6513b85f51510e51090e205715
URL: https://github.com/llvm/llvm-project/commit/3a696f6092effe6513b85f51510e51090e205715
DIFF: https://github.com/llvm/llvm-project/commit/3a696f6092effe6513b85f51510e51090e205715.diff
LOG: [InstCombine] rotate(X,Z) eq/ne rotate(Y,Z) ---> X eq/ne Y (PR51565)
```
----------------------------------------
define i1 @src(i8 %x, i8 %y, i8 %z) {
%0:
%f = fshl i8 %x, i8 %x, i8 %z
%f2 = fshl i8 %y, i8 %y, i8 %z
%r = icmp eq i8 %f, %f2
ret i1 %r
}
=>
define i1 @tgt(i8 %x, i8 %y, i8 %z) {
%0:
%r = icmp eq i8 %x, %y
ret i1 %r
}
Transformation seems to be correct!
```
https://alive2.llvm.org/ce/z/qAZp8f
Solves PR51565
Reviewed By: spatel
Differential Revision: https://reviews.llvm.org/D109271
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
llvm/test/Transforms/InstCombine/icmp-rotate.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 7d303164e5cf3..4cc795647dbee 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3261,6 +3261,42 @@ Instruction *InstCombinerImpl::foldICmpEqIntrinsicWithConstant(
return nullptr;
}
+/// Fold an icmp with LLVM intrinsics
+static Instruction *foldICmpIntrinsicWithIntrinsic(ICmpInst &Cmp) {
+ assert(Cmp.isEquality());
+
+ ICmpInst::Predicate Pred = Cmp.getPredicate();
+ Value *Op0 = Cmp.getOperand(0);
+ Value *Op1 = Cmp.getOperand(1);
+ const auto *IIOp0 = dyn_cast<IntrinsicInst>(Op0);
+ const auto *IIOp1 = dyn_cast<IntrinsicInst>(Op1);
+ if (!IIOp0 || !IIOp1 || IIOp0->getIntrinsicID() != IIOp1->getIntrinsicID())
+ return nullptr;
+
+ switch (IIOp0->getIntrinsicID()) {
+ case Intrinsic::bswap:
+ case Intrinsic::bitreverse:
+ // If both operands are byte-swapped or bit-reversed, just compare the
+ // original values.
+ return new ICmpInst(Pred, IIOp0->getOperand(0), IIOp1->getOperand(0));
+ case Intrinsic::fshl:
+ case Intrinsic::fshr:
+ // If both operands are rotated by same amount, just compare the
+ // original values.
+ if (IIOp0->getOperand(0) != IIOp0->getOperand(1))
+ break;
+ if (IIOp1->getOperand(0) != IIOp1->getOperand(1))
+ break;
+ if (IIOp0->getOperand(2) != IIOp1->getOperand(2))
+ break;
+ return new ICmpInst(Pred, IIOp0->getOperand(0), IIOp1->getOperand(0));
+ default:
+ break;
+ }
+
+ return nullptr;
+}
+
/// Fold an icmp with LLVM intrinsic and constant operand: icmp Pred II, C.
Instruction *InstCombinerImpl::foldICmpIntrinsicWithConstant(ICmpInst &Cmp,
IntrinsicInst *II,
@@ -4478,14 +4514,8 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
}
}
- // If both operands are byte-swapped or bit-reversed, just compare the
- // original values.
- // TODO: Move this to a function similar to foldICmpIntrinsicWithConstant()
- // and handle more intrinsics.
- if ((match(Op0, m_BSwap(m_Value(A))) && match(Op1, m_BSwap(m_Value(B)))) ||
- (match(Op0, m_BitReverse(m_Value(A))) &&
- match(Op1, m_BitReverse(m_Value(B)))))
- return new ICmpInst(Pred, A, B);
+ if (Instruction *ICmp = foldICmpIntrinsicWithIntrinsic(I))
+ return ICmp;
// Canonicalize checking for a power-of-2-or-zero value:
// (A & (A-1)) == 0 --> ctpop(A) < 2 (two commuted variants)
diff --git a/llvm/test/Transforms/InstCombine/icmp-rotate.ll b/llvm/test/Transforms/InstCombine/icmp-rotate.ll
index cf670c79e7a4d..30e3e6aa2d1ad 100644
--- a/llvm/test/Transforms/InstCombine/icmp-rotate.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-rotate.ll
@@ -9,9 +9,7 @@ declare void @use(i8)
define i1 @rol_eq(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @rol_eq(
-; CHECK-NEXT: [[F:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Z:%.*]])
-; CHECK-NEXT: [[F2:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[Z]])
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[F]], [[F2]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%f = tail call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %z)
@@ -22,9 +20,7 @@ define i1 @rol_eq(i8 %x, i8 %y, i8 %z) {
define i1 @rol_ne(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @rol_ne(
-; CHECK-NEXT: [[F:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Z:%.*]])
-; CHECK-NEXT: [[F2:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[Z]])
-; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[F]], [[F2]]
+; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%f = tail call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %z)
@@ -35,9 +31,7 @@ define i1 @rol_ne(i8 %x, i8 %y, i8 %z) {
define i1 @ror_eq(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @ror_eq(
-; CHECK-NEXT: [[F:%.*]] = tail call i8 @llvm.fshr.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Z:%.*]])
-; CHECK-NEXT: [[F2:%.*]] = tail call i8 @llvm.fshr.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[Z]])
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[F]], [[F2]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%f = tail call i8 @llvm.fshr.i8(i8 %x, i8 %x, i8 %z)
@@ -49,9 +43,7 @@ define i1 @ror_eq(i8 %x, i8 %y, i8 %z) {
define i1 @ror_ne(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @ror_ne(
-; CHECK-NEXT: [[F:%.*]] = tail call i8 @llvm.fshr.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Z:%.*]])
-; CHECK-NEXT: [[F2:%.*]] = tail call i8 @llvm.fshr.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[Z]])
-; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[F]], [[F2]]
+; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%f = tail call i8 @llvm.fshr.i8(i8 %x, i8 %x, i8 %z)
@@ -64,8 +56,7 @@ define i1 @rol_eq_use(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @rol_eq_use(
; CHECK-NEXT: [[F:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Z:%.*]])
; CHECK-NEXT: call void @use(i8 [[F]])
-; CHECK-NEXT: [[F2:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[Z]])
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[F]], [[F2]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[X]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%f = tail call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %z)
@@ -81,7 +72,7 @@ define i1 @rol_eq_uses(i8 %x, i8 %y, i8 %z) {
; CHECK-NEXT: call void @use(i8 [[F]])
; CHECK-NEXT: [[F2:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[Z]])
; CHECK-NEXT: call void @use(i8 [[F2]])
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[F]], [[F2]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[X]], [[Y]]
; CHECK-NEXT: ret i1 [[R]]
;
%f = tail call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %z)
@@ -94,9 +85,7 @@ define i1 @rol_eq_uses(i8 %x, i8 %y, i8 %z) {
define <2 x i1> @rol_eq_vec(<2 x i5> %x, <2 x i5> %y, <2 x i5> %z) {
; CHECK-LABEL: @rol_eq_vec(
-; CHECK-NEXT: [[F:%.*]] = tail call <2 x i5> @llvm.fshl.v2i5(<2 x i5> [[X:%.*]], <2 x i5> [[X]], <2 x i5> [[Z:%.*]])
-; CHECK-NEXT: [[F2:%.*]] = tail call <2 x i5> @llvm.fshl.v2i5(<2 x i5> [[Y:%.*]], <2 x i5> [[Y]], <2 x i5> [[Z]])
-; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i5> [[F]], [[F2]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i5> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%f = tail call <2 x i5> @llvm.fshl.v2i5(<2 x i5> %x, <2 x i5> %x, <2 x i5> %z)
@@ -107,9 +96,7 @@ define <2 x i1> @rol_eq_vec(<2 x i5> %x, <2 x i5> %y, <2 x i5> %z) {
define <2 x i1> @ror_eq_vec(<2 x i5> %x, <2 x i5> %y, <2 x i5> %z) {
; CHECK-LABEL: @ror_eq_vec(
-; CHECK-NEXT: [[F:%.*]] = tail call <2 x i5> @llvm.fshr.v2i5(<2 x i5> [[X:%.*]], <2 x i5> [[X]], <2 x i5> [[Z:%.*]])
-; CHECK-NEXT: [[F2:%.*]] = tail call <2 x i5> @llvm.fshr.v2i5(<2 x i5> [[Y:%.*]], <2 x i5> [[Y]], <2 x i5> [[Z]])
-; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i5> [[F]], [[F2]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i5> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%f = tail call <2 x i5> @llvm.fshr.v2i5(<2 x i5> %x, <2 x i5> %x, <2 x i5> %z)
More information about the llvm-commits
mailing list