[InstCombine] fold not-shift of signbit to icmp+zext, part 2
Follow-up to:
6c39a3aae1
That converted a pattern with ashr directly to icmp+zext, and
this updates the pattern that we used to convert to.
This canonicalizes to icmp for better analysis in the minimum case
and shortens patterns where the source type is not the same as dest type:
https://alive2.llvm.org/ce/z/tpXJ64
https://alive2.llvm.org/ce/z/dQ405O
This requires an adjustment to an icmp transform to avoid infinite looping.
This commit is contained in:
@@ -1027,8 +1027,11 @@ Instruction *InstCombinerImpl::transformZExtICmp(ICmpInst *Cmp, ZExtInst &Zext)
|
||||
// If Op1C some other power of two, convert:
|
||||
KnownBits Known = computeKnownBits(Cmp->getOperand(0), 0, &Zext);
|
||||
|
||||
// Exactly 1 possible 1? But not the high-bit because that is
|
||||
// canonicalized to this form.
|
||||
APInt KnownZeroMask(~Known.Zero);
|
||||
if (KnownZeroMask.isPowerOf2()) { // Exactly 1 possible 1?
|
||||
if (KnownZeroMask.isPowerOf2() &&
|
||||
(Zext.getType()->getScalarSizeInBits() != KnownZeroMask.logBase2() + 1)) {
|
||||
bool isNE = Cmp->getPredicate() == ICmpInst::ICMP_NE;
|
||||
uint32_t ShAmt = KnownZeroMask.logBase2();
|
||||
Value *In = Cmp->getOperand(0);
|
||||
|
||||
@@ -1091,10 +1091,17 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) {
|
||||
|
||||
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
||||
Type *Ty = I.getType();
|
||||
Value *X;
|
||||
const APInt *C;
|
||||
unsigned BitWidth = Ty->getScalarSizeInBits();
|
||||
|
||||
// (iN (~X) u>> (N - 1)) --> zext (X > -1)
|
||||
if (match(Op0, m_OneUse(m_Not(m_Value(X)))) &&
|
||||
match(Op1, m_SpecificIntAllowUndef(BitWidth - 1)))
|
||||
return new ZExtInst(Builder.CreateIsNotNeg(X, "isnotneg"), Ty);
|
||||
|
||||
if (match(Op1, m_APInt(C))) {
|
||||
unsigned ShAmtC = C->getZExtValue();
|
||||
unsigned BitWidth = Ty->getScalarSizeInBits();
|
||||
auto *II = dyn_cast<IntrinsicInst>(Op0);
|
||||
if (II && isPowerOf2_32(BitWidth) && Log2_32(BitWidth) == ShAmtC &&
|
||||
(II->getIntrinsicID() == Intrinsic::ctlz ||
|
||||
@@ -1320,7 +1327,6 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) {
|
||||
}
|
||||
|
||||
// Transform (x << y) >> y to x & (-1 >> y)
|
||||
Value *X;
|
||||
if (match(Op0, m_OneUse(m_Shl(m_Value(X), m_Specific(Op1))))) {
|
||||
Constant *AllOnes = ConstantInt::getAllOnesValue(Ty);
|
||||
Value *Mask = Builder.CreateLShr(AllOnes, Op1);
|
||||
|
||||
@@ -28,9 +28,9 @@ define i32 @test2(i32 %x, i32 %y, i32 %z) {
|
||||
|
||||
define i32 @PR38781(i32 %a, i32 %b) {
|
||||
; CHECK-LABEL: @PR38781(
|
||||
; CHECK-NEXT: [[B_LOBIT_NOT1_DEMORGAN:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
|
||||
; CHECK-NEXT: [[B_LOBIT_NOT1:%.*]] = xor i32 [[B_LOBIT_NOT1_DEMORGAN]], -1
|
||||
; CHECK-NEXT: [[AND:%.*]] = lshr i32 [[B_LOBIT_NOT1]], 31
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], -1
|
||||
; CHECK-NEXT: [[AND:%.*]] = zext i1 [[TMP2]] to i32
|
||||
; CHECK-NEXT: ret i32 [[AND]]
|
||||
;
|
||||
%a.lobit = lshr i32 %a, 31
|
||||
|
||||
@@ -19,10 +19,10 @@ define i32 @sterix(i32, i8, i64) {
|
||||
; CHECK-NEXT: [[AND:%.*]] = and i64 [[MUL3]], [[TMP2]]
|
||||
; CHECK-NEXT: [[CONV4:%.*]] = trunc i64 [[AND]] to i32
|
||||
; CHECK-NEXT: [[TOBOOL7_NOT:%.*]] = icmp eq i32 [[CONV4]], 0
|
||||
; CHECK-NEXT: [[PHITMP:%.*]] = zext i1 [[TOBOOL7_NOT]] to i32
|
||||
; CHECK-NEXT: [[PHI_CAST:%.*]] = zext i1 [[TOBOOL7_NOT]] to i32
|
||||
; CHECK-NEXT: br label [[LOR_END]]
|
||||
; CHECK: lor.end:
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[PHITMP]], [[LOR_RHS]] ]
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[PHI_CAST]], [[LOR_RHS]] ]
|
||||
; CHECK-NEXT: ret i32 [[TMP4]]
|
||||
;
|
||||
entry:
|
||||
|
||||
@@ -947,8 +947,8 @@ define i32 @not_narrow_bswap(i24 %x) {
|
||||
|
||||
define i8 @not_signbit(i8 %x) {
|
||||
; CHECK-LABEL: @not_signbit(
|
||||
; CHECK-NEXT: [[A:%.*]] = xor i8 [[X:%.*]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = lshr i8 [[A]], 7
|
||||
; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt i8 [[X:%.*]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = zext i1 [[ISNOTNEG]] to i8
|
||||
; CHECK-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%a = xor i8 %x, -1
|
||||
@@ -958,8 +958,8 @@ define i8 @not_signbit(i8 %x) {
|
||||
|
||||
define <2 x i6> @not_signbit_vec(<2 x i6> %x) {
|
||||
; CHECK-LABEL: @not_signbit_vec(
|
||||
; CHECK-NEXT: [[A:%.*]] = xor <2 x i6> [[X:%.*]], <i6 -1, i6 poison>
|
||||
; CHECK-NEXT: [[R:%.*]] = lshr <2 x i6> [[A]], <i6 5, i6 poison>
|
||||
; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt <2 x i6> [[X:%.*]], <i6 -1, i6 -1>
|
||||
; CHECK-NEXT: [[R:%.*]] = zext <2 x i1> [[ISNOTNEG]] to <2 x i6>
|
||||
; CHECK-NEXT: ret <2 x i6> [[R]]
|
||||
;
|
||||
%a = xor <2 x i6> %x, <i6 -1, i6 poison>
|
||||
@@ -969,8 +969,8 @@ define <2 x i6> @not_signbit_vec(<2 x i6> %x) {
|
||||
|
||||
define i8 @not_signbit_alt_xor(i8 %x) {
|
||||
; CHECK-LABEL: @not_signbit_alt_xor(
|
||||
; CHECK-NEXT: [[A:%.*]] = xor i8 [[X:%.*]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = lshr i8 [[A]], 7
|
||||
; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt i8 [[X:%.*]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = zext i1 [[ISNOTNEG]] to i8
|
||||
; CHECK-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%a = xor i8 %x, -2
|
||||
@@ -1004,9 +1004,8 @@ define i32 @not_signbit_use(i32 %x) {
|
||||
|
||||
define i32 @not_signbit_zext(i16 %x) {
|
||||
; CHECK-LABEL: @not_signbit_zext(
|
||||
; CHECK-NEXT: [[A:%.*]] = xor i16 [[X:%.*]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = lshr i16 [[A]], 15
|
||||
; CHECK-NEXT: [[R2:%.*]] = zext i16 [[R]] to i32
|
||||
; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt i16 [[X:%.*]], -1
|
||||
; CHECK-NEXT: [[R2:%.*]] = zext i1 [[ISNOTNEG]] to i32
|
||||
; CHECK-NEXT: ret i32 [[R2]]
|
||||
;
|
||||
%a = xor i16 %x, -1
|
||||
@@ -1017,9 +1016,8 @@ define i32 @not_signbit_zext(i16 %x) {
|
||||
|
||||
define i8 @not_signbit_trunc(i16 %x) {
|
||||
; CHECK-LABEL: @not_signbit_trunc(
|
||||
; CHECK-NEXT: [[A:%.*]] = xor i16 [[X:%.*]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = lshr i16 [[A]], 15
|
||||
; CHECK-NEXT: [[R2:%.*]] = trunc i16 [[R]] to i8
|
||||
; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt i16 [[X:%.*]], -1
|
||||
; CHECK-NEXT: [[R2:%.*]] = zext i1 [[ISNOTNEG]] to i8
|
||||
; CHECK-NEXT: ret i8 [[R2]]
|
||||
;
|
||||
%a = xor i16 %x, -1
|
||||
|
||||
@@ -233,9 +233,8 @@ define i8 @neg_signbit_use2(i5 %x) {
|
||||
|
||||
define i32 @neg_not_signbit1(i8 %x) {
|
||||
; CHECK-LABEL: @neg_not_signbit1(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X:%.*]], -1
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = lshr i8 [[TMP1]], 7
|
||||
; CHECK-NEXT: [[R:%.*]] = zext i8 [[TMP2]] to i32
|
||||
; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt i8 [[X:%.*]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = zext i1 [[ISNOTNEG]] to i32
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%s = lshr i8 %x, 7
|
||||
|
||||
@@ -1061,8 +1061,8 @@ define i8 @not_lshr(i8 %x) {
|
||||
|
||||
define <2 x i8> @not_lshr_vec(<2 x i8> %x) {
|
||||
; CHECK-LABEL: @not_lshr_vec(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
|
||||
; CHECK-NEXT: [[R:%.*]] = lshr <2 x i8> [[TMP1]], <i8 7, i8 7>
|
||||
; CHECK-NEXT: [[ISNOTNEG:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
|
||||
; CHECK-NEXT: [[R:%.*]] = zext <2 x i1> [[ISNOTNEG]] to <2 x i8>
|
||||
; CHECK-NEXT: ret <2 x i8> [[R]]
|
||||
;
|
||||
%a = lshr <2 x i8> %x, <i8 7, i8 7>
|
||||
|
||||
@@ -501,10 +501,10 @@ define i8 @notneg_zext_narrower_use(i32 %x) {
|
||||
|
||||
define i8 @disguised_signbit_clear_test(i64 %x) {
|
||||
; CHECK-LABEL: @disguised_signbit_clear_test(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[X:%.*]] to i8
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = xor i8 [[TMP1]], -1
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = lshr i8 [[TMP2]], 7
|
||||
; CHECK-NEXT: ret i8 [[TMP3]]
|
||||
; CHECK-NEXT: [[A1:%.*]] = and i64 [[X:%.*]], 128
|
||||
; CHECK-NEXT: [[T4:%.*]] = icmp eq i64 [[A1]], 0
|
||||
; CHECK-NEXT: [[T6:%.*]] = zext i1 [[T4]] to i8
|
||||
; CHECK-NEXT: ret i8 [[T6]]
|
||||
;
|
||||
%a1 = and i64 %x, 128
|
||||
%t4 = icmp eq i64 %a1, 0
|
||||
|
||||
Reference in New Issue
Block a user