[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