[llvm] [InstCombine] Fold ashr((zext (xor X, C)) - 1, 31) to sext(X == C) (PR #228983)

Suyoung Oh via llvm-commits llvm-commits at lists.llvm.org
Sun Oct 4 23:37:04 PDT 2026


=?utf-8?b?7Jik7IiY7JiB?= <ohsusu515 at gmail.com>
Message-ID: <llvm.org/llvm/llvm-project/pull/228983 at github.com>
In-Reply-To:


https://github.com/wimmings created https://github.com/llvm/llvm-project/pull/228983

Fixes #227763

This adds an InstCombine fold for:

```text
ashr((zext (xor X, C)) - 1, 31)
  -> sext(X == C)
```

`X xor C` is zero exactly when `X == C`. Zero-extension followed by
subtracting one and arithmetic shifting by the sign bit produces an all-ones
mask only for that equality case, which is equivalent to sign-extending the
comparison.

Alive2 proof: https://alive2.llvm.org/ce/z/Ff8C2q

Regression tests cover scalar, vector, narrow-width, multi-use, and
non-matching cases.

Tests:
```text
ninja -C build check-llvm-transforms-instcombine
```

Result:
```text
Total Discovered Tests: 1888
Unsupported: 140
Passed: 1748
```

Additional references:
- Godbolt: https://godbolt.org/z/4zM1d89n4
- Compiler Explorer: https://compiler-explorer.com/z/5sechMWMh

>From f63257a6bd1869655cb8be5b5388213737011677 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=98=A4=EC=88=98=EC=98=81?= <ohsusu515 at gmail.com>
Date: Thu, 1 Oct 2026 01:56:50 +0900
Subject: [PATCH 1/2] [InstCombine] Precommit tests for XOR equality-mask fold

---
 .../InstCombine/ashr-xor-equality-mask.ll     | 261 ++++++++++++++++++
 1 file changed, 261 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/ashr-xor-equality-mask.ll

diff --git a/llvm/test/Transforms/InstCombine/ashr-xor-equality-mask.ll b/llvm/test/Transforms/InstCombine/ashr-xor-equality-mask.ll
new file mode 100644
index 0000000000000..b90d5b554c360
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/ashr-xor-equality-mask.ll
@@ -0,0 +1,261 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare void @use_i8(i8)
+declare void @use_i32(i32)
+
+; https://github.com/llvm/llvm-project/issues/227763
+define i32 @xor_eq_mask(i8 %x) {
+; CHECK-LABEL: define i32 @xor_eq_mask(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X]], 3
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[XOR]] to i32
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
+; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    ret i32 [[MASK]]
+;
+entry:
+  %xor = xor i8 %x, 3
+  %zext = zext i8 %xor to i32
+  %sub = add nsw i32 %zext, -1
+  %mask = ashr i32 %sub, 31
+  ret i32 %mask
+}
+
+; Check that the fold is not hard-coded specifically for C = 3.
+define i32 @xor_eq_mask_other_constant(i8 %x) {
+; CHECK-LABEL: define i32 @xor_eq_mask_other_constant(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X]], 42
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[XOR]] to i32
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
+; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    ret i32 [[MASK]]
+;
+entry:
+  %xor = xor i8 %x, 42
+  %zext = zext i8 %xor to i32
+  %sub = add nsw i32 %zext, -1
+  %mask = ashr i32 %sub, 31
+  ret i32 %mask
+}
+
+; The add cannot overflow because zext produces a value in [0, 255],
+; so the fold should not require an explicit nsw flag.
+define i32 @xor_eq_mask_no_nsw(i8 %x) {
+; CHECK-LABEL: define i32 @xor_eq_mask_no_nsw(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X]], 3
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[XOR]] to i32
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
+; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    ret i32 [[MASK]]
+;
+entry:
+  %xor = xor i8 %x, 3
+  %zext = zext i8 %xor to i32
+  %sub = add i32 %zext, -1
+  %mask = ashr i32 %sub, 31
+  ret i32 %mask
+}
+
+; The xor has another use, but folding the mask is still profitable.
+define i32 @xor_eq_mask_xor_multi_use(i8 %x) {
+; CHECK-LABEL: define i32 @xor_eq_mask_xor_multi_use(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X]], 3
+; CHECK-NEXT:    call void @use_i8(i8 [[XOR]])
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[XOR]] to i32
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
+; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    ret i32 [[MASK]]
+;
+entry:
+  %xor = xor i8 %x, 3
+  call void @use_i8(i8 %xor)
+  %zext = zext i8 %xor to i32
+  %sub = add nsw i32 %zext, -1
+  %mask = ashr i32 %sub, 31
+  ret i32 %mask
+}
+
+; The add has another use. Replacing only the ashr could increase the
+; instruction count, so this checks the profitability restriction.
+define i32 @xor_eq_mask_sub_multi_use(i8 %x) {
+; CHECK-LABEL: define i32 @xor_eq_mask_sub_multi_use(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X]], 3
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[XOR]] to i32
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
+; CHECK-NEXT:    call void @use_i32(i32 [[SUB]])
+; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    ret i32 [[MASK]]
+;
+entry:
+  %xor = xor i8 %x, 3
+  %zext = zext i8 %xor to i32
+  %sub = add nsw i32 %zext, -1
+  call void @use_i32(i32 %sub)
+  %mask = ashr i32 %sub, 31
+  ret i32 %mask
+}
+
+; Negative test: shifting by 7 does not produce only 0 or -1.
+define i32 @xor_eq_mask_wrong_shift(i8 %x) {
+; CHECK-LABEL: define i32 @xor_eq_mask_wrong_shift(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X]], 3
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[XOR]] to i32
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
+; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 7
+; CHECK-NEXT:    ret i32 [[MASK]]
+;
+entry:
+  %xor = xor i8 %x, 3
+  %zext = zext i8 %xor to i32
+  %sub = add nsw i32 %zext, -1
+  %mask = ashr i32 %sub, 7
+  ret i32 %mask
+}
+
+; Negative test: subtracting 2 detects more than just X == 3.
+define i32 @xor_eq_mask_wrong_addend(i8 %x) {
+; CHECK-LABEL: define i32 @xor_eq_mask_wrong_addend(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X]], 2
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[XOR]] to i32
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -2
+; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    ret i32 [[MASK]]
+;
+entry:
+  %xor = xor i8 %x, 3
+  %zext = zext i8 %xor to i32
+  %sub = add nsw i32 %zext, -2
+  %mask = ashr i32 %sub, 31
+  ret i32 %mask
+}
+
+; Record the behavior for a splat vector.
+define <2 x i32> @xor_eq_mask_vec_splat(<2 x i8> %x) {
+; CHECK-LABEL: define <2 x i32> @xor_eq_mask_vec_splat(
+; CHECK-SAME: <2 x i8> [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i8> [[X]], splat (i8 3)
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[XOR]] to <2 x i32>
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw <2 x i32> [[ZEXT]], splat (i32 -1)
+; CHECK-NEXT:    [[MASK:%.*]] = ashr <2 x i32> [[SUB]], splat (i32 31)
+; CHECK-NEXT:    ret <2 x i32> [[MASK]]
+;
+entry:
+  %xor = xor <2 x i8> %x, <i8 3, i8 3>
+  %zext = zext <2 x i8> %xor to <2 x i32>
+  %sub = add nsw <2 x i32> %zext, <i32 -1, i32 -1>
+  %mask = ashr <2 x i32> %sub, <i32 31, i32 31>
+  ret <2 x i32> %mask
+}
+
+; Test the core fold without an xor.
+define i32 @zext_zero_mask(i8 %x) {
+; CHECK-LABEL: define i32 @zext_zero_mask(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[X]] to i32
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
+; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    ret i32 [[MASK]]
+;
+entry:
+  %zext = zext i8 %x to i32
+  %sub = add i32 %zext, -1
+  %mask = ashr i32 %sub, 31
+  ret i32 %mask
+}
+
+define i8 @zext_zero_mask_i4_i8(i4 %x) {
+; CHECK-LABEL: define i8 @zext_zero_mask_i4_i8(
+; CHECK-SAME: i4 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i4 [[X]] to i8
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i8 [[ZEXT]], -1
+; CHECK-NEXT:    [[MASK:%.*]] = ashr i8 [[SUB]], 7
+; CHECK-NEXT:    ret i8 [[MASK]]
+;
+entry:
+  %zext = zext i4 %x to i8
+  %sub = add i8 %zext, -1
+  %mask = ashr i8 %sub, 7
+  ret i8 %mask
+}
+
+define i8 @zext_zero_mask_i7_i8(i7 %x) {
+; CHECK-LABEL: define i8 @zext_zero_mask_i7_i8(
+; CHECK-SAME: i7 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i7 [[X]] to i8
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i8 [[ZEXT]], -1
+; CHECK-NEXT:    [[MASK:%.*]] = ashr i8 [[SUB]], 7
+; CHECK-NEXT:    ret i8 [[MASK]]
+;
+entry:
+  %zext = zext i7 %x to i8
+  %sub = add i8 %zext, -1
+  %mask = ashr i8 %sub, 7
+  ret i8 %mask
+}
+
+define <2 x i32> @zext_zero_mask_vec(<2 x i8> %x) {
+; CHECK-LABEL: define <2 x i32> @zext_zero_mask_vec(
+; CHECK-SAME: <2 x i8> [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[X]] to <2 x i32>
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw <2 x i32> [[ZEXT]], splat (i32 -1)
+; CHECK-NEXT:    [[MASK:%.*]] = ashr <2 x i32> [[SUB]], splat (i32 31)
+; CHECK-NEXT:    ret <2 x i32> [[MASK]]
+;
+entry:
+  %zext = zext <2 x i8> %x to <2 x i32>
+  %sub = add <2 x i32> %zext, <i32 -1, i32 -1>
+  %mask = ashr <2 x i32> %sub, <i32 31, i32 31>
+  ret <2 x i32> %mask
+}
+
+define i8 @zext_zero_mask_i1_i8(i1 %x) {
+; CHECK-LABEL: define i8 @zext_zero_mask_i1_i8(
+; CHECK-SAME: i1 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[NOT_X:%.*]] = xor i1 [[X]], true
+; CHECK-NEXT:    [[SUB:%.*]] = sext i1 [[NOT_X]] to i8
+; CHECK-NEXT:    ret i8 [[SUB]]
+;
+entry:
+  %zext = zext i1 %x to i8
+  %sub = add i8 %zext, -1
+  %mask = ashr i8 %sub, 7
+  ret i8 %mask
+}
+
+define i32 @zext_zero_mask_zext_multi_use(i8 %x) {
+; CHECK-LABEL: define i32 @zext_zero_mask_zext_multi_use(
+; CHECK-SAME: i8 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[X]] to i32
+; CHECK-NEXT:    call void @use_i32(i32 [[ZEXT]])
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
+; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    ret i32 [[MASK]]
+;
+entry:
+  %zext = zext i8 %x to i32
+  call void @use_i32(i32 %zext)
+  %sub = add i32 %zext, -1
+  %mask = ashr i32 %sub, 31
+  ret i32 %mask
+}

>From 91d387eaf888b894ba68af93e4b346cdd8046f46 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=98=A4=EC=88=98=EC=98=81?= <ohsusu515 at gmail.com>
Date: Mon, 5 Oct 2026 14:48:44 +0900
Subject: [PATCH 2/2] [InstCombine] Fold XOR equality masks to icmp/sext

---
 .../InstCombine/InstCombineShifts.cpp         |  4 ++
 .../InstCombine/ashr-xor-equality-mask.ll     | 53 +++++++------------
 2 files changed, 24 insertions(+), 33 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
index 97964cebb50b8..dd35bc9ff2970 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -1910,6 +1910,10 @@ Instruction *InstCombinerImpl::visitAShr(BinaryOperator &I) {
       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);
+
+      // ashr (add (zext X), -1), BitWidth-1 --> sext (X == 0)
+      if (match(Op0, m_OneUse(m_Add(m_ZExt(m_Value(X)), m_AllOnes()))))
+        return new SExtInst(Builder.CreateIsNull(X), Ty);
     }
 
     const APInt *MulC;
diff --git a/llvm/test/Transforms/InstCombine/ashr-xor-equality-mask.ll b/llvm/test/Transforms/InstCombine/ashr-xor-equality-mask.ll
index b90d5b554c360..0979492a9a76d 100644
--- a/llvm/test/Transforms/InstCombine/ashr-xor-equality-mask.ll
+++ b/llvm/test/Transforms/InstCombine/ashr-xor-equality-mask.ll
@@ -9,10 +9,8 @@ define i32 @xor_eq_mask(i8 %x) {
 ; CHECK-LABEL: define i32 @xor_eq_mask(
 ; CHECK-SAME: i8 [[X:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X]], 3
-; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[XOR]] to i32
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
-; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq i8 [[X]], 3
+; CHECK-NEXT:    [[MASK:%.*]] = sext i1 [[TMP0]] to i32
 ; CHECK-NEXT:    ret i32 [[MASK]]
 ;
 entry:
@@ -28,10 +26,8 @@ define i32 @xor_eq_mask_other_constant(i8 %x) {
 ; CHECK-LABEL: define i32 @xor_eq_mask_other_constant(
 ; CHECK-SAME: i8 [[X:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X]], 42
-; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[XOR]] to i32
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
-; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq i8 [[X]], 42
+; CHECK-NEXT:    [[MASK:%.*]] = sext i1 [[TMP0]] to i32
 ; CHECK-NEXT:    ret i32 [[MASK]]
 ;
 entry:
@@ -48,10 +44,8 @@ define i32 @xor_eq_mask_no_nsw(i8 %x) {
 ; CHECK-LABEL: define i32 @xor_eq_mask_no_nsw(
 ; CHECK-SAME: i8 [[X:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X]], 3
-; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[XOR]] to i32
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
-; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq i8 [[X]], 3
+; CHECK-NEXT:    [[MASK:%.*]] = sext i1 [[TMP0]] to i32
 ; CHECK-NEXT:    ret i32 [[MASK]]
 ;
 entry:
@@ -69,9 +63,8 @@ define i32 @xor_eq_mask_xor_multi_use(i8 %x) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X]], 3
 ; CHECK-NEXT:    call void @use_i8(i8 [[XOR]])
-; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[XOR]] to i32
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
-; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq i8 [[X]], 3
+; CHECK-NEXT:    [[MASK:%.*]] = sext i1 [[TMP0]] to i32
 ; CHECK-NEXT:    ret i32 [[MASK]]
 ;
 entry:
@@ -148,10 +141,8 @@ define <2 x i32> @xor_eq_mask_vec_splat(<2 x i8> %x) {
 ; CHECK-LABEL: define <2 x i32> @xor_eq_mask_vec_splat(
 ; CHECK-SAME: <2 x i8> [[X:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i8> [[X]], splat (i8 3)
-; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[XOR]] to <2 x i32>
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw <2 x i32> [[ZEXT]], splat (i32 -1)
-; CHECK-NEXT:    [[MASK:%.*]] = ashr <2 x i32> [[SUB]], splat (i32 31)
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq <2 x i8> [[X]], splat (i8 3)
+; CHECK-NEXT:    [[MASK:%.*]] = sext <2 x i1> [[TMP0]] to <2 x i32>
 ; CHECK-NEXT:    ret <2 x i32> [[MASK]]
 ;
 entry:
@@ -167,9 +158,8 @@ define i32 @zext_zero_mask(i8 %x) {
 ; CHECK-LABEL: define i32 @zext_zero_mask(
 ; CHECK-SAME: i8 [[X:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[X]] to i32
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
-; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq i8 [[X]], 0
+; CHECK-NEXT:    [[MASK:%.*]] = sext i1 [[TMP0]] to i32
 ; CHECK-NEXT:    ret i32 [[MASK]]
 ;
 entry:
@@ -183,9 +173,8 @@ define i8 @zext_zero_mask_i4_i8(i4 %x) {
 ; CHECK-LABEL: define i8 @zext_zero_mask_i4_i8(
 ; CHECK-SAME: i4 [[X:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[ZEXT:%.*]] = zext i4 [[X]] to i8
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw i8 [[ZEXT]], -1
-; CHECK-NEXT:    [[MASK:%.*]] = ashr i8 [[SUB]], 7
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq i4 [[X]], 0
+; CHECK-NEXT:    [[MASK:%.*]] = sext i1 [[TMP0]] to i8
 ; CHECK-NEXT:    ret i8 [[MASK]]
 ;
 entry:
@@ -199,9 +188,8 @@ define i8 @zext_zero_mask_i7_i8(i7 %x) {
 ; CHECK-LABEL: define i8 @zext_zero_mask_i7_i8(
 ; CHECK-SAME: i7 [[X:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[ZEXT:%.*]] = zext i7 [[X]] to i8
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw i8 [[ZEXT]], -1
-; CHECK-NEXT:    [[MASK:%.*]] = ashr i8 [[SUB]], 7
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq i7 [[X]], 0
+; CHECK-NEXT:    [[MASK:%.*]] = sext i1 [[TMP0]] to i8
 ; CHECK-NEXT:    ret i8 [[MASK]]
 ;
 entry:
@@ -215,9 +203,8 @@ define <2 x i32> @zext_zero_mask_vec(<2 x i8> %x) {
 ; CHECK-LABEL: define <2 x i32> @zext_zero_mask_vec(
 ; CHECK-SAME: <2 x i8> [[X:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[X]] to <2 x i32>
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw <2 x i32> [[ZEXT]], splat (i32 -1)
-; CHECK-NEXT:    [[MASK:%.*]] = ashr <2 x i32> [[SUB]], splat (i32 31)
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq <2 x i8> [[X]], zeroinitializer
+; CHECK-NEXT:    [[MASK:%.*]] = sext <2 x i1> [[TMP0]] to <2 x i32>
 ; CHECK-NEXT:    ret <2 x i32> [[MASK]]
 ;
 entry:
@@ -248,8 +235,8 @@ define i32 @zext_zero_mask_zext_multi_use(i8 %x) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[X]] to i32
 ; CHECK-NEXT:    call void @use_i32(i32 [[ZEXT]])
-; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[ZEXT]], -1
-; CHECK-NEXT:    [[MASK:%.*]] = ashr i32 [[SUB]], 31
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq i8 [[X]], 0
+; CHECK-NEXT:    [[MASK:%.*]] = sext i1 [[TMP0]] to i32
 ; CHECK-NEXT:    ret i32 [[MASK]]
 ;
 entry:



More information about the llvm-commits mailing list