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);
if (ShiftAmt->uge(TypeBits))
return nullptr;
- ICmpInst::Predicate Pred = Cmp.getPredicate();
Value *X = Shl->getOperand(0);
Type *ShType = Shl->getType();
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
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
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
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
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
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
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
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
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