[llvm] 52fac60 - [InstCombine] Fold `[l|a]shr iN (X-1)&~X, N-1 -> [z|s]ext(X==0)` (#107259)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 6 06:37:55 PDT 2024
Author: Yingwei Zheng
Date: 2024-09-06T21:37:50+08:00
New Revision: 52fac608bd3fb93caf08c137cea4591372aa8f31
URL: https://github.com/llvm/llvm-project/commit/52fac608bd3fb93caf08c137cea4591372aa8f31
DIFF: https://github.com/llvm/llvm-project/commit/52fac608bd3fb93caf08c137cea4591372aa8f31.diff
LOG: [InstCombine] Fold `[l|a]shr iN (X-1)&~X, N-1 -> [z|s]ext(X==0)` (#107259)
Alive2: https://alive2.llvm.org/ce/z/kwvTFn
Closes #107228.
`ashr iN (X-1)&~X, N-1` also exists. See
https://github.com/dtcxzyw/llvm-opt-benchmark/issues/1274.
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
llvm/test/Transforms/InstCombine/ashr-lshr.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
index 794b384d126eb6..10c3ccdb2243a1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -1478,6 +1478,11 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) {
Value *Signbit = Builder.CreateLShr(X, ShAmtC);
return BinaryOperator::CreateAnd(Signbit, X);
}
+
+ // lshr iN (X - 1) & ~X, N-1 --> zext (X == 0)
+ if (match(Op0, m_OneUse(m_c_And(m_Add(m_Value(X), m_AllOnes()),
+ m_Not(m_Deferred(X))))))
+ return new ZExtInst(Builder.CreateIsNull(X), Ty);
}
Instruction *TruncSrc;
@@ -1754,6 +1759,11 @@ Instruction *InstCombinerImpl::visitAShr(BinaryOperator &I) {
Value *Y;
if (match(Op0, m_OneUse(m_NSWSub(m_Value(X), m_Value(Y)))))
return new SExtInst(Builder.CreateICmpSLT(X, Y), Ty);
+
+ // ashr iN (X - 1) & ~X, N-1 --> sext (X == 0)
+ if (match(Op0, m_OneUse(m_c_And(m_Add(m_Value(X), m_AllOnes()),
+ m_Not(m_Deferred(X))))))
+ return new SExtInst(Builder.CreateIsNull(X), Ty);
}
const APInt *MulC;
diff --git a/llvm/test/Transforms/InstCombine/ashr-lshr.ll b/llvm/test/Transforms/InstCombine/ashr-lshr.ll
index 9e31c9b0738c61..49041906680b3a 100644
--- a/llvm/test/Transforms/InstCombine/ashr-lshr.ll
+++ b/llvm/test/Transforms/InstCombine/ashr-lshr.ll
@@ -874,4 +874,207 @@ define i32 @ashr_mul_times_5_div_4_exact_2(i32 %x) {
ret i32 %ashr
}
+
+define i32 @lsb_mask_sign_zext(i32 %x) {
+; CHECK-LABEL: @lsb_mask_sign_zext(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT: [[SHR:%.*]] = zext i1 [[TMP0]] to i32
+; CHECK-NEXT: ret i32 [[SHR]]
+;
+entry:
+ %sub = add i32 %x, -1
+ %not = xor i32 %x, -1
+ %and = and i32 %sub, %not
+ %shr = lshr i32 %and, 31
+ ret i32 %shr
+}
+
+define i32 @lsb_mask_sign_zext_commuted(i32 %x) {
+; CHECK-LABEL: @lsb_mask_sign_zext_commuted(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT: [[SHR:%.*]] = zext i1 [[TMP0]] to i32
+; CHECK-NEXT: ret i32 [[SHR]]
+;
+entry:
+ %sub = add i32 %x, -1
+ %not = xor i32 %x, -1
+ %and = and i32 %not, %sub
+ %shr = lshr i32 %and, 31
+ ret i32 %shr
+}
+
+; Negative tests
+
+define i32 @lsb_mask_sign_zext_wrong_cst1(i32 %x) {
+; CHECK-LABEL: @lsb_mask_sign_zext_wrong_cst1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[SUB:%.*]] = add i32 [[X:%.*]], -2
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[X]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[SUB]], [[NOT]]
+; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[AND]], 31
+; CHECK-NEXT: ret i32 [[SHR]]
+;
+entry:
+ %sub = add i32 %x, -2
+ %not = xor i32 %x, -1
+ %and = and i32 %sub, %not
+ %shr = lshr i32 %and, 31
+ ret i32 %shr
+}
+
+define i32 @lsb_mask_sign_zext_wrong_cst2(i32 %x) {
+; CHECK-LABEL: @lsb_mask_sign_zext_wrong_cst2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[SUB:%.*]] = add i32 [[X:%.*]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[SUB]], [[X]]
+; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[AND]], 31
+; CHECK-NEXT: ret i32 [[SHR]]
+;
+entry:
+ %sub = add i32 %x, -1
+ %not = xor i32 %x, 2
+ %and = and i32 %sub, %not
+ %shr = lshr i32 %and, 31
+ ret i32 %shr
+}
+
+define i32 @lsb_mask_sign_zext_wrong_cst3(i32 %x) {
+; CHECK-LABEL: @lsb_mask_sign_zext_wrong_cst3(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[SUB:%.*]] = add i32 [[X:%.*]], -1
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[X]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[SUB]], [[NOT]]
+; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[AND]], 30
+; CHECK-NEXT: ret i32 [[SHR]]
+;
+entry:
+ %sub = add i32 %x, -1
+ %not = xor i32 %x, -1
+ %and = and i32 %sub, %not
+ %shr = lshr i32 %and, 30
+ ret i32 %shr
+}
+
+define i32 @lsb_mask_sign_zext_multiuse(i32 %x) {
+; CHECK-LABEL: @lsb_mask_sign_zext_multiuse(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[SUB:%.*]] = add i32 [[X:%.*]], -1
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[X]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[SUB]], [[NOT]]
+; CHECK-NEXT: call void @use(i32 [[AND]])
+; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[AND]], 31
+; CHECK-NEXT: ret i32 [[SHR]]
+;
+entry:
+ %sub = add i32 %x, -1
+ %not = xor i32 %x, -1
+ %and = and i32 %sub, %not
+ call void @use(i32 %and)
+ %shr = lshr i32 %and, 31
+ ret i32 %shr
+}
+
+define i32 @lsb_mask_sign_sext(i32 %x) {
+; CHECK-LABEL: @lsb_mask_sign_sext(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT: [[SHR:%.*]] = sext i1 [[TMP0]] to i32
+; CHECK-NEXT: ret i32 [[SHR]]
+;
+entry:
+ %sub = add i32 %x, -1
+ %not = xor i32 %x, -1
+ %and = and i32 %sub, %not
+ %shr = ashr i32 %and, 31
+ ret i32 %shr
+}
+
+define i32 @lsb_mask_sign_sext_commuted(i32 %x) {
+; CHECK-LABEL: @lsb_mask_sign_sext_commuted(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT: [[SHR:%.*]] = sext i1 [[TMP0]] to i32
+; CHECK-NEXT: ret i32 [[SHR]]
+;
+entry:
+ %sub = add i32 %x, -1
+ %not = xor i32 %x, -1
+ %and = and i32 %not, %sub
+ %shr = ashr i32 %and, 31
+ ret i32 %shr
+}
+
+; Negative tests
+
+define i32 @lsb_mask_sign_sext_wrong_cst1(i32 %x) {
+; CHECK-LABEL: @lsb_mask_sign_sext_wrong_cst1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[SUB:%.*]] = add i32 [[X:%.*]], -2
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[X]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[SUB]], [[NOT]]
+; CHECK-NEXT: [[SHR:%.*]] = ashr i32 [[AND]], 31
+; CHECK-NEXT: ret i32 [[SHR]]
+;
+entry:
+ %sub = add i32 %x, -2
+ %not = xor i32 %x, -1
+ %and = and i32 %sub, %not
+ %shr = ashr i32 %and, 31
+ ret i32 %shr
+}
+
+define i32 @lsb_mask_sign_sext_wrong_cst2(i32 %x) {
+; CHECK-LABEL: @lsb_mask_sign_sext_wrong_cst2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[SUB:%.*]] = add i32 [[X:%.*]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[SUB]], [[X]]
+; CHECK-NEXT: [[SHR:%.*]] = ashr i32 [[AND]], 31
+; CHECK-NEXT: ret i32 [[SHR]]
+;
+entry:
+ %sub = add i32 %x, -1
+ %not = xor i32 %x, 2
+ %and = and i32 %sub, %not
+ %shr = ashr i32 %and, 31
+ ret i32 %shr
+}
+
+define i32 @lsb_mask_sign_sext_wrong_cst3(i32 %x) {
+; CHECK-LABEL: @lsb_mask_sign_sext_wrong_cst3(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[SUB:%.*]] = add i32 [[X:%.*]], -1
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[X]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[SUB]], [[NOT]]
+; CHECK-NEXT: [[SHR:%.*]] = ashr i32 [[AND]], 30
+; CHECK-NEXT: ret i32 [[SHR]]
+;
+entry:
+ %sub = add i32 %x, -1
+ %not = xor i32 %x, -1
+ %and = and i32 %sub, %not
+ %shr = ashr i32 %and, 30
+ ret i32 %shr
+}
+
+define i32 @lsb_mask_sign_sext_multiuse(i32 %x) {
+; CHECK-LABEL: @lsb_mask_sign_sext_multiuse(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[SUB:%.*]] = add i32 [[X:%.*]], -1
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[X]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[SUB]], [[NOT]]
+; CHECK-NEXT: call void @use(i32 [[AND]])
+; CHECK-NEXT: [[SHR:%.*]] = ashr i32 [[AND]], 31
+; CHECK-NEXT: ret i32 [[SHR]]
+;
+entry:
+ %sub = add i32 %x, -1
+ %not = xor i32 %x, -1
+ %and = and i32 %sub, %not
+ call void @use(i32 %and)
+ %shr = ashr i32 %and, 31
+ ret i32 %shr
+}
+
declare void @use(i32)
More information about the llvm-commits
mailing list