[InstSimplify] Simplify `(shl nsw nuw X, BitWidth - 1)` -> `0`
authorNoah Goldstein <goldstein.w.n@gmail.com>
Tue, 7 Mar 2023 00:12:49 +0000 (18:12 -0600)
committerNoah Goldstein <goldstein.w.n@gmail.com>
Tue, 7 Mar 2023 02:29:53 +0000 (20:29 -0600)
https://alive2.llvm.org/ce/z/uFy5zT

Reviewed By: nikic, spatel

Differential Revision: https://reviews.llvm.org/D145327

llvm/lib/Analysis/InstructionSimplify.cpp
llvm/test/Transforms/InstSimplify/shift.ll

index d6f3585..abcde1d 100644 (file)
@@ -1445,10 +1445,11 @@ static Value *simplifyShlInst(Value *Op0, Value *Op1, bool IsNSW, bool IsNUW,
           simplifyShift(Instruction::Shl, Op0, Op1, IsNSW, Q, MaxRecurse))
     return V;
 
+  Type *Ty = Op0->getType();
   // undef << X -> 0
   // undef << X -> undef if (if it's NSW/NUW)
   if (Q.isUndefValue(Op0))
-    return IsNSW || IsNUW ? Op0 : Constant::getNullValue(Op0->getType());
+    return IsNSW || IsNUW ? Op0 : Constant::getNullValue(Ty);
 
   // (X >> A) << A -> X
   Value *X;
@@ -1462,6 +1463,13 @@ static Value *simplifyShlInst(Value *Op0, Value *Op1, bool IsNSW, bool IsNUW,
   // NOTE: could use computeKnownBits() / LazyValueInfo,
   // but the cost-benefit analysis suggests it isn't worth it.
 
+  // "nuw" guarantees that only zeros are shifted out, and "nsw" guarantees
+  // that the sign-bit does not change, so the only input that does not
+  // produce poison is 0, and "0 << (bitwidth-1) --> 0".
+  if (IsNSW && IsNUW &&
+      match(Op1, m_SpecificInt(Ty->getScalarSizeInBits() - 1)))
+    return Constant::getNullValue(Ty);
+
   return nullptr;
 }
 
index 4fda696..8375176 100644 (file)
@@ -354,8 +354,7 @@ define <vscale x 4 x i16> @lshr_scalable_overshift(<vscale x 4 x i16> %va) {
 ; shl nsw+nuw is 0
 define i8 @shl_nsw_nuw_7_eq_0(i8 %x) {
 ; CHECK-LABEL: @shl_nsw_nuw_7_eq_0(
-; CHECK-NEXT:    [[Y:%.*]] = shl nuw nsw i8 [[X:%.*]], 7
-; CHECK-NEXT:    ret i8 [[Y]]
+; CHECK-NEXT:    ret i8 0
 ;
   %y = shl nsw nuw i8 %x, 7
   ret i8 %y
@@ -364,8 +363,7 @@ define i8 @shl_nsw_nuw_7_eq_0(i8 %x) {
 ; Make sure we match the element width
 define <2 x i8> @shl_vec_nsw_nuw_7_eq_0(<2 x i8> %x) {
 ; CHECK-LABEL: @shl_vec_nsw_nuw_7_eq_0(
-; CHECK-NEXT:    [[Y:%.*]] = shl nuw nsw <2 x i8> [[X:%.*]], <i8 7, i8 7>
-; CHECK-NEXT:    ret <2 x i8> [[Y]]
+; CHECK-NEXT:    ret <2 x i8> zeroinitializer
 ;
   %y = shl nsw nuw <2 x i8> %x, <i8 7, i8 7>
   ret <2 x i8> %y