[llvm] 73ce343 - [InstCombine] Add transform `(icmp pred (shl {nsw and/or nuw} X, Y), C)` -> `(icmp pred X, C)`
Noah Goldstein via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 5 11:01:13 PDT 2023
Author: Noah Goldstein
Date: 2023-06-05T13:01:03-05:00
New Revision: 73ce343125c5c86373ac3f883932f4ddbc2d307a
URL: https://github.com/llvm/llvm-project/commit/73ce343125c5c86373ac3f883932f4ddbc2d307a
DIFF: https://github.com/llvm/llvm-project/commit/73ce343125c5c86373ac3f883932f4ddbc2d307a.diff
LOG: [InstCombine] Add transform `(icmp pred (shl {nsw and/or nuw} X, Y), C)` -> `(icmp pred X, C)`
Three new transforms:
1) `(icmp pred (shl nsw nuw X, Y), C)` [if `C <= 0`] -> `(icmp pred X, C)`
- ugt: https://alive2.llvm.org/ce/z/K_57J_
- sgt: https://alive2.llvm.org/ce/z/BL8u_a
- sge: https://alive2.llvm.org/ce/z/yZZVYz
- uge: https://alive2.llvm.org/ce/z/R4jwwJ
- ule: https://alive2.llvm.org/ce/z/-gbmth
- sle: https://alive2.llvm.org/ce/z/ycZVsh
- slt: https://alive2.llvm.org/ce/z/4MzHYm
- sle: https://alive2.llvm.org/ce/z/fgNfex
- ult: https://alive2.llvm.org/ce/z/cXfvH5
- eq : https://alive2.llvm.org/ce/z/sZh_Ti
- ne : https://alive2.llvm.org/ce/z/UrqSWA
2) `(icmp eq/ne (shl {nsw|nuw} X, Y), 0)` -> `(icmp eq/ne X, 0)`
- eq+nsw: https://alive2.llvm.org/ce/z/aSJN6D
- eq+nuw: https://alive2.llvm.org/ce/z/r2_-br
- ne+nuw: https://alive2.llvm.org/ce/z/RkETtu
- ne+nsw: https://alive2.llvm.org/ce/z/8iSfW3
3) `(icmp slt (shl nsw X, Y), 0/1)` -> `(icmp pred X, 0/1)`
`(icmp sgt (shl nsw X, Y), 0/-1)` -> `(icmp pred X, 0/-1)`
- slt: https://alive2.llvm.org/ce/z/eZYRan
- sgt: https://alive2.llvm.org/ce/z/QQeP26
Transform 3) is really sle/slt/sge/sgt with 0, but sle/sge
canonicalize to slt/sgt respectively so its implemented as such.
Reviewed By: nikic
Differential Revision: https://reviews.llvm.org/D145341
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
llvm/test/Transforms/InstCombine/icmp-shl.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 5770ece470aee..e80d69c77545e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2189,6 +2189,32 @@ Instruction *InstCombinerImpl::foldICmpShlConstant(ICmpInst &Cmp,
if (Cmp.isEquality() && match(Shl->getOperand(0), m_APInt(ShiftVal)))
return foldICmpShlConstConst(Cmp, Shl->getOperand(1), C, *ShiftVal);
+ ICmpInst::Predicate Pred = Cmp.getPredicate();
+ // (icmp pred (shl nuw&nsw X, Y), Csle0)
+ // -> (icmp pred X, Csle0)
+ //
+ // The idea is the nuw/nsw essentially freeze the sign bit for the shift op
+ // so X's must be what is used.
+ if (C.sle(0) && Shl->hasNoUnsignedWrap() && Shl->hasNoSignedWrap())
+ return new ICmpInst(Pred, Shl->getOperand(0), Cmp.getOperand(1));
+
+ // (icmp eq/ne (shl nuw|nsw X, Y), 0)
+ // -> (icmp eq/ne X, 0)
+ if (ICmpInst::isEquality(Pred) && C.isZero() &&
+ (Shl->hasNoUnsignedWrap() || Shl->hasNoSignedWrap()))
+ return new ICmpInst(Pred, Shl->getOperand(0), Cmp.getOperand(1));
+
+ // (icmp slt (shl nsw X, Y), 0/1)
+ // -> (icmp slt X, 0/1)
+ // (icmp sgt (shl nsw X, Y), 0/-1)
+ // -> (icmp sgt X, 0/-1)
+ //
+ // NB: sge/sle with a constant will canonicalize to sgt/slt.
+ if (Shl->hasNoSignedWrap() &&
+ (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLT))
+ if (C.isZero() || (Pred == ICmpInst::ICMP_SGT ? C.isAllOnes() : C.isOne()))
+ return new ICmpInst(Pred, Shl->getOperand(0), Cmp.getOperand(1));
+
const APInt *ShiftAmt;
if (!match(Shl->getOperand(1), m_APInt(ShiftAmt)))
return foldICmpShlOne(Cmp, Shl, C);
@@ -2199,7 +2225,6 @@ Instruction *InstCombinerImpl::foldICmpShlConstant(ICmpInst &Cmp,
if (ShiftAmt->uge(TypeBits))
return nullptr;
- ICmpInst::Predicate Pred = Cmp.getPredicate();
Value *X = Shl->getOperand(0);
Type *ShType = Shl->getType();
diff --git a/llvm/test/Transforms/InstCombine/icmp-shl.ll b/llvm/test/Transforms/InstCombine/icmp-shl.ll
index b69f60acdf739..5295bd01aa089 100644
--- a/llvm/test/Transforms/InstCombine/icmp-shl.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-shl.ll
@@ -3,8 +3,7 @@
define i1 @shl_nuw_eq_0(i8 %x, i8 %C) {
; CHECK-LABEL: @shl_nuw_eq_0(
-; CHECK-NEXT: [[Y:%.*]] = shl nuw i8 [[X:%.*]], [[C:%.*]]
-; CHECK-NEXT: [[Z:%.*]] = icmp eq i8 [[Y]], 0
+; CHECK-NEXT: [[Z:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT: ret i1 [[Z]]
;
%y = shl nuw i8 %x, %C
@@ -14,8 +13,7 @@ define i1 @shl_nuw_eq_0(i8 %x, i8 %C) {
define <2 x i1> @shl_nsw_ne_0(<2 x i8> %x, <2 x i8> %C) {
; CHECK-LABEL: @shl_nsw_ne_0(
-; CHECK-NEXT: [[Y:%.*]] = shl nsw <2 x i8> [[X:%.*]], [[C:%.*]]
-; CHECK-NEXT: [[Z:%.*]] = icmp ne <2 x i8> [[Y]], zeroinitializer
+; CHECK-NEXT: [[Z:%.*]] = icmp ne <2 x i8> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[Z]]
;
%y = shl nsw <2 x i8> %x, %C
@@ -47,8 +45,7 @@ define i1 @shl_ne_1_fail_nonzero(i8 %x, i8 %C) {
define i1 @shl_nsw_slt_1(i8 %x, i8 %C) {
; CHECK-LABEL: @shl_nsw_slt_1(
-; CHECK-NEXT: [[Y:%.*]] = shl nsw i8 [[X:%.*]], [[C:%.*]]
-; CHECK-NEXT: [[Z:%.*]] = icmp slt i8 [[Y]], 1
+; CHECK-NEXT: [[Z:%.*]] = icmp slt i8 [[X:%.*]], 1
; CHECK-NEXT: ret i1 [[Z]]
;
%y = shl nsw i8 %x, %C
@@ -80,8 +77,7 @@ define <2 x i1> @shl_nsw_sle_n1(<2 x i8> %x, <2 x i8> %C) {
define <2 x i1> @shl_nsw_sge_1(<2 x i8> %x, <2 x i8> %C) {
; CHECK-LABEL: @shl_nsw_sge_1(
-; CHECK-NEXT: [[Y:%.*]] = shl nsw <2 x i8> [[X:%.*]], [[C:%.*]]
-; CHECK-NEXT: [[Z:%.*]] = icmp sgt <2 x i8> [[Y]], zeroinitializer
+; CHECK-NEXT: [[Z:%.*]] = icmp sgt <2 x i8> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[Z]]
;
%y = shl nsw <2 x i8> %x, %C
@@ -91,8 +87,7 @@ define <2 x i1> @shl_nsw_sge_1(<2 x i8> %x, <2 x i8> %C) {
define i1 @shl_nsw_sgt_n1(i8 %x, i8 %C) {
; CHECK-LABEL: @shl_nsw_sgt_n1(
-; CHECK-NEXT: [[Y:%.*]] = shl nsw i8 [[X:%.*]], [[C:%.*]]
-; CHECK-NEXT: [[Z:%.*]] = icmp sgt i8 [[Y]], -1
+; CHECK-NEXT: [[Z:%.*]] = icmp sgt i8 [[X:%.*]], -1
; CHECK-NEXT: ret i1 [[Z]]
;
%y = shl nsw i8 %x, %C
@@ -113,8 +108,7 @@ define i1 @shl_nuw_sgt_n1_fail_wrong_flag(i8 %x, i8 %C) {
define i1 @shl_nsw_nuw_ult_Csle0(i8 %x, i8 %C) {
; CHECK-LABEL: @shl_nsw_nuw_ult_Csle0(
-; CHECK-NEXT: [[Y:%.*]] = shl nuw nsw i8 [[X:%.*]], [[C:%.*]]
-; CHECK-NEXT: [[Z:%.*]] = icmp ult i8 [[Y]], -19
+; CHECK-NEXT: [[Z:%.*]] = icmp ult i8 [[X:%.*]], -19
; CHECK-NEXT: ret i1 [[Z]]
;
%y = shl nuw nsw i8 %x, %C
@@ -135,8 +129,7 @@ define i1 @shl_nsw_ule_Csle0_fail_missing_flag(i8 %x, i8 %C) {
define i1 @shl_nsw_nuw_uge_Csle0(i8 %x, i8 %C) {
; CHECK-LABEL: @shl_nsw_nuw_uge_Csle0(
-; CHECK-NEXT: [[Y:%.*]] = shl nuw nsw i8 [[X:%.*]], [[C:%.*]]
-; CHECK-NEXT: [[Z:%.*]] = icmp ugt i8 [[Y]], -121
+; CHECK-NEXT: [[Z:%.*]] = icmp ugt i8 [[X:%.*]], -121
; CHECK-NEXT: ret i1 [[Z]]
;
%y = shl nuw nsw i8 %x, %C
@@ -157,8 +150,7 @@ define i1 @shl_nuw_ugt_Csle0_fail_missing_flag(i8 %x, i8 %C) {
define <2 x i1> @shl_nsw_nuw_sgt_Csle0(<2 x i8> %x, <2 x i8> %C) {
; CHECK-LABEL: @shl_nsw_nuw_sgt_Csle0(
-; CHECK-NEXT: [[Y:%.*]] = shl nuw nsw <2 x i8> [[X:%.*]], [[C:%.*]]
-; CHECK-NEXT: [[Z:%.*]] = icmp sgt <2 x i8> [[Y]], <i8 -10, i8 -10>
+; CHECK-NEXT: [[Z:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -10, i8 -10>
; CHECK-NEXT: ret <2 x i1> [[Z]]
;
%y = shl nsw nuw <2 x i8> %x, %C
@@ -179,8 +171,7 @@ define <2 x i1> @shl_nsw_nuw_sge_Csle0_todo_non_splat(<2 x i8> %x, <2 x i8> %C)
define <2 x i1> @shl_nsw_nuw_sle_Csle0(<2 x i8> %x, <2 x i8> %C) {
; CHECK-LABEL: @shl_nsw_nuw_sle_Csle0(
-; CHECK-NEXT: [[Y:%.*]] = shl nuw nsw <2 x i8> [[X:%.*]], [[C:%.*]]
-; CHECK-NEXT: [[Z:%.*]] = icmp slt <2 x i8> [[Y]], <i8 -5, i8 -5>
+; CHECK-NEXT: [[Z:%.*]] = icmp slt <2 x i8> [[X:%.*]], <i8 -5, i8 -5>
; CHECK-NEXT: ret <2 x i1> [[Z]]
;
%y = shl nsw nuw <2 x i8> %x, %C
More information about the llvm-commits
mailing list