diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -1229,6 +1229,10 @@ }; computeKnownBitsFromShiftOperator(I, DemandedElts, Known, Known2, Depth, Q, KF); + // Trailing zeros of a right-shifted constant never decrease. + const APInt *C; + if (match(I->getOperand(0), m_APInt(C))) + Known.Zero.setLowBits(C->countTrailingZeros()); break; } case Instruction::LShr: { @@ -1237,6 +1241,10 @@ }; computeKnownBitsFromShiftOperator(I, DemandedElts, Known, Known2, Depth, Q, KF); + // Leading zeros of a left-shifted constant never decrease. + const APInt *C; + if (match(I->getOperand(0), m_APInt(C))) + Known.Zero.setHighBits(C->countLeadingZeros()); break; } case Instruction::AShr: { diff --git a/llvm/test/Transforms/InstCombine/and2.ll b/llvm/test/Transforms/InstCombine/and2.ll --- a/llvm/test/Transforms/InstCombine/and2.ll +++ b/llvm/test/Transforms/InstCombine/and2.ll @@ -181,26 +181,22 @@ ret <2 x i8> %and } -; (1 >> x) & 1 --> zext(x == 0) +; The mask is unnecessary. define i8 @and1_lshr1_is_cmp_eq_0(i8 %x) { ; CHECK-LABEL: @and1_lshr1_is_cmp_eq_0( -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], 0 -; CHECK-NEXT: [[AND:%.*]] = zext i1 [[TMP1]] to i8 -; CHECK-NEXT: ret i8 [[AND]] +; CHECK-NEXT: [[SH:%.*]] = lshr i8 1, [[X:%.*]] +; CHECK-NEXT: ret i8 [[SH]] ; %sh = lshr i8 1, %x %and = and i8 %sh, 1 ret i8 %and } -; Don't do it if the shift has another use. - define i8 @and1_lshr1_is_cmp_eq_0_multiuse(i8 %x) { ; CHECK-LABEL: @and1_lshr1_is_cmp_eq_0_multiuse( ; CHECK-NEXT: [[SH:%.*]] = lshr i8 1, [[X:%.*]] -; CHECK-NEXT: [[AND:%.*]] = and i8 [[SH]], 1 -; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i8 [[SH]], [[AND]] +; CHECK-NEXT: [[ADD:%.*]] = shl nuw nsw i8 [[SH]], 1 ; CHECK-NEXT: ret i8 [[ADD]] ; %sh = lshr i8 1, %x @@ -209,13 +205,12 @@ ret i8 %add } -; (1 >> x) & 1 --> zext(x == 0) +; The mask is unnecessary. define <2 x i8> @and1_lshr1_is_cmp_eq_0_vec(<2 x i8> %x) { ; CHECK-LABEL: @and1_lshr1_is_cmp_eq_0_vec( -; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i8> [[X:%.*]], zeroinitializer -; CHECK-NEXT: [[AND:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i8> -; CHECK-NEXT: ret <2 x i8> [[AND]] +; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i8> , [[X:%.*]] +; CHECK-NEXT: ret <2 x i8> [[SH]] ; %sh = lshr <2 x i8> , %x %and = and <2 x i8> %sh, diff --git a/llvm/test/Transforms/InstCombine/lshr-and-negC-icmpeq-zero.ll b/llvm/test/Transforms/InstCombine/lshr-and-negC-icmpeq-zero.ll --- a/llvm/test/Transforms/InstCombine/lshr-and-negC-icmpeq-zero.ll +++ b/llvm/test/Transforms/InstCombine/lshr-and-negC-icmpeq-zero.ll @@ -179,12 +179,13 @@ ; Negative tests -; X is constant +; TODO: This could be reduced to lshr+icmp ult. define i1 @scalar_i32_lshr_and_negC_eq_X_is_constant1(i32 %y) { ; CHECK-LABEL: @scalar_i32_lshr_and_negC_eq_X_is_constant1( ; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 12345, [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ult i32 [[LSHR]], 8 +; CHECK-NEXT: [[AND:%.*]] = and i32 [[LSHR]], 16376 +; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[AND]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %lshr = lshr i32 12345, %y @@ -193,10 +194,13 @@ ret i1 %r } +; TODO: This could be reduced to lshr+icmp ult. + define i1 @scalar_i32_lshr_and_negC_eq_X_is_constant2(i32 %y) { ; CHECK-LABEL: @scalar_i32_lshr_and_negC_eq_X_is_constant2( ; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 268435456, [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ult i32 [[LSHR]], 8 +; CHECK-NEXT: [[AND:%.*]] = and i32 [[LSHR]], 536870904 +; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[AND]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %lshr = lshr i32 268435456, %y diff --git a/llvm/test/Transforms/InstCombine/shift.ll b/llvm/test/Transforms/InstCombine/shift.ll --- a/llvm/test/Transforms/InstCombine/shift.ll +++ b/llvm/test/Transforms/InstCombine/shift.ll @@ -1799,7 +1799,7 @@ define i8 @lshr_mask_demand(i8 %x) { ; CHECK-LABEL: @lshr_mask_demand( ; CHECK-NEXT: [[S:%.*]] = lshr i8 63, [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = and i8 [[S]], -32 +; CHECK-NEXT: [[R:%.*]] = and i8 [[S]], 32 ; CHECK-NEXT: ret i8 [[R]] ; %s = lshr i8 63, %x ; 0b00111111 @@ -1810,7 +1810,7 @@ define i8 @shl_mask_demand(i8 %x) { ; CHECK-LABEL: @shl_mask_demand( ; CHECK-NEXT: [[S:%.*]] = shl i8 12, [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = and i8 [[S]], 7 +; CHECK-NEXT: [[R:%.*]] = and i8 [[S]], 4 ; CHECK-NEXT: ret i8 [[R]] ; %s = shl i8 12, %x ; 0b00001100 diff --git a/llvm/test/Transforms/InstCombine/signbit-shl-and-icmpeq-zero.ll b/llvm/test/Transforms/InstCombine/signbit-shl-and-icmpeq-zero.ll --- a/llvm/test/Transforms/InstCombine/signbit-shl-and-icmpeq-zero.ll +++ b/llvm/test/Transforms/InstCombine/signbit-shl-and-icmpeq-zero.ll @@ -187,10 +187,7 @@ define i1 @scalar_i32_signbit_shl_and_eq_X_is_constant1(i32 %y) { ; CHECK-LABEL: @scalar_i32_signbit_shl_and_eq_X_is_constant1( -; CHECK-NEXT: [[SHL:%.*]] = shl i32 -2147483648, [[Y:%.*]] -; CHECK-NEXT: [[AND:%.*]] = and i32 [[SHL]], 12345 -; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 true ; %shl = shl i32 2147483648, %y %and = and i32 %shl, 12345 @@ -200,10 +197,7 @@ define i1 @scalar_i32_signbit_shl_and_eq_X_is_constant2(i32 %y) { ; CHECK-LABEL: @scalar_i32_signbit_shl_and_eq_X_is_constant2( -; CHECK-NEXT: [[SHL:%.*]] = shl i32 -2147483648, [[Y:%.*]] -; CHECK-NEXT: [[AND:%.*]] = and i32 [[SHL]], 1 -; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 true ; %shl = shl i32 2147483648, %y %and = and i32 %shl, 1 @@ -219,7 +213,7 @@ ; CHECK-LABEL: @scalar_i32_signbit_shl_and_slt( ; CHECK-NEXT: [[SHL:%.*]] = shl i32 -2147483648, [[Y:%.*]] ; CHECK-NEXT: [[AND:%.*]] = and i32 [[SHL]], [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp slt i32 [[AND]], 0 +; CHECK-NEXT: [[R:%.*]] = icmp ne i32 [[AND]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %shl = shl i32 2147483648, %y @@ -232,10 +226,7 @@ define i1 @scalar_i32_signbit_shl_and_eq_nonzero(i32 %x, i32 %y) { ; CHECK-LABEL: @scalar_i32_signbit_shl_and_eq_nonzero( -; CHECK-NEXT: [[SHL:%.*]] = shl i32 -2147483648, [[Y:%.*]] -; CHECK-NEXT: [[AND:%.*]] = and i32 [[SHL]], [[X:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp eq i32 [[AND]], 1 -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 false ; %shl = shl i32 2147483648, %y %and = and i32 %shl, %x diff --git a/llvm/test/Transforms/InstCombine/zext-or-icmp.ll b/llvm/test/Transforms/InstCombine/zext-or-icmp.ll --- a/llvm/test/Transforms/InstCombine/zext-or-icmp.ll +++ b/llvm/test/Transforms/InstCombine/zext-or-icmp.ll @@ -49,10 +49,7 @@ ; CHECK-NEXT: br label [[BLOCK2]] ; CHECK: block2: ; CHECK-NEXT: [[CMP_I:%.*]] = phi i1 [ false, [[BLOCK1:%.*]] ], [ true, [[ENTRY:%.*]] ] -; CHECK-NEXT: [[M_011:%.*]] = phi i32 [ 0, [[BLOCK1]] ], [ 33, [[ENTRY]] ] -; CHECK-NEXT: [[M_1_OP:%.*]] = lshr i32 1, [[M_011]] -; CHECK-NEXT: [[SEXT_MASK:%.*]] = and i32 [[M_1_OP]], 65535 -; CHECK-NEXT: [[CMP115:%.*]] = icmp ne i32 [[SEXT_MASK]], 0 +; CHECK-NEXT: [[CMP115:%.*]] = phi i1 [ true, [[BLOCK1]] ], [ false, [[ENTRY]] ] ; CHECK-NEXT: [[CMP1:%.*]] = or i1 [[CMP_I]], [[CMP115]] ; CHECK-NEXT: [[CONV2:%.*]] = zext i1 [[CMP1]] to i32 ; CHECK-NEXT: ret i32 [[CONV2]] @@ -82,10 +79,7 @@ ; CHECK-NEXT: br label [[BLOCK2]] ; CHECK: block2: ; CHECK-NEXT: [[CMP_I:%.*]] = phi i1 [ false, [[BLOCK1:%.*]] ], [ true, [[ENTRY:%.*]] ] -; CHECK-NEXT: [[M_011:%.*]] = phi i32 [ 0, [[BLOCK1]] ], [ 33, [[ENTRY]] ] -; CHECK-NEXT: [[M_1_OP:%.*]] = lshr i32 1, [[M_011]] -; CHECK-NEXT: [[SEXT_MASK:%.*]] = and i32 [[M_1_OP]], 65535 -; CHECK-NEXT: [[CMP115:%.*]] = icmp ne i32 [[SEXT_MASK]], 0 +; CHECK-NEXT: [[CMP115:%.*]] = phi i1 [ true, [[BLOCK1]] ], [ false, [[ENTRY]] ] ; CHECK-NEXT: [[CMP1:%.*]] = or i1 [[CMP_I]], [[CMP115]] ; CHECK-NEXT: [[CONV2:%.*]] = zext i1 [[CMP1]] to i32 ; CHECK-NEXT: ret i32 [[CONV2]]