[llvm] [X86] Use BMI2 shrx for range-known zero tests (PR #207904)
Jaeuk Lee via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 7 01:07:31 PDT 2026
https://github.com/skku970412 updated https://github.com/llvm/llvm-project/pull/207904
>From 457923193e46bc429bfa626bc9a11f44fd07151a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=9A=B1?=
<126692701+skku970412 at users.noreply.github.com>
Date: Tue, 7 Jul 2026 15:35:07 +0900
Subject: [PATCH 1/2] [X86] Use BMI2 shrx for range-known zero tests
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 50 +++++++++++++
llvm/test/CodeGen/X86/setcc.ll | 94 ++++++++++++++++++++++++-
2 files changed, 143 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 9209134a055c6..1a830690761df 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -57313,6 +57313,53 @@ static SDValue combineExtSetcc(SDNode *N, SelectionDAG &DAG,
return Res;
}
+static SDValue combineZextSetccEqZeroToShift(SDNode *N, SelectionDAG &DAG,
+ const X86Subtarget &Subtarget) {
+ if (!Subtarget.hasBMI2() || !Subtarget.is64Bit() ||
+ N->getOpcode() != ISD::ZERO_EXTEND)
+ return SDValue();
+
+ SDValue N0 = N->getOperand(0);
+ if (N0.getOpcode() != ISD::SETCC || !N0.hasOneUse())
+ return SDValue();
+
+ ISD::CondCode CC = cast<CondCodeSDNode>(N0.getOperand(2))->get();
+ if (CC != ISD::SETEQ)
+ return SDValue();
+
+ SDValue X = N0.getOperand(0);
+ SDValue Y = N0.getOperand(1);
+ if (isNullConstant(X))
+ std::swap(X, Y);
+ else if (!isNullConstant(Y))
+ return SDValue();
+
+ EVT ShiftVT = X.getValueType();
+ EVT VT = N->getValueType(0);
+ if (!ShiftVT.isSimple() || !ShiftVT.isScalarInteger() ||
+ !VT.isSimple() || !VT.isScalarInteger())
+ return SDValue();
+
+ MVT ShiftMVT = ShiftVT.getSimpleVT();
+ if (ShiftMVT != MVT::i32 && ShiftMVT != MVT::i64)
+ return SDValue();
+ MVT ResultMVT = VT.getSimpleVT();
+ if (ResultMVT != MVT::i32 && ResultMVT != MVT::i64)
+ return SDValue();
+
+ unsigned BitWidth = ShiftMVT.getScalarSizeInBits();
+ if (!DAG.computeKnownBits(X).getMaxValue().ult(BitWidth))
+ return SDValue();
+
+ // SHRX masks its shift count, so this is only equivalent to zext(X == 0)
+ // when the shift amount is known to be in range. Under that condition,
+ // (1 >> X) produces 1 iff X is zero and 0 otherwise.
+ SDLoc DL(N);
+ SDValue One = DAG.getConstant(1, DL, ShiftMVT);
+ SDValue Shift = DAG.getNode(ISD::SRL, DL, ShiftMVT, One, X);
+ return DAG.getZExtOrTrunc(Shift, DL, VT);
+}
+
static SDValue combineSext(SDNode *N, SelectionDAG &DAG,
TargetLowering::DAGCombinerInfo &DCI,
const X86Subtarget &Subtarget) {
@@ -57643,6 +57690,9 @@ static SDValue combineZext(SDNode *N, SelectionDAG &DAG,
if (SDValue V = combineExtSetcc(N, DAG, Subtarget))
return V;
+ if (SDValue V = combineZextSetccEqZeroToShift(N, DAG, Subtarget))
+ return V;
+
if (SDValue V = combineToExtendBoolVectorInReg(N->getOpcode(), dl, VT, N0,
DAG, DCI, Subtarget))
return V;
diff --git a/llvm/test/CodeGen/X86/setcc.ll b/llvm/test/CodeGen/X86/setcc.ll
index 60ac6df3f77af..3ab8a15ed54d4 100644
--- a/llvm/test/CodeGen/X86/setcc.ll
+++ b/llvm/test/CodeGen/X86/setcc.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc < %s -mtriple=i686-apple-darwin | FileCheck %s --check-prefixes=X86
; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s --check-prefixes=X64,X64-NOTBM,X64-NOBMI2
; RUN: llc < %s -mtriple=x86_64-apple-darwin -mattr=+tbm | FileCheck %s --check-prefixes=X64,X64-NOBMI2,X64-TBM
@@ -354,3 +354,95 @@ define i64 @pr63055(double %arg) {
%ext = zext i1 %fcmp to i64
ret i64 %ext
}
+
+define i32 @zext_eq_zero_i32(i32 %a) {
+; X86-LABEL: zext_eq_zero_i32:
+; X86: ## %bb.0:
+; X86-NEXT: xorl %eax, %eax
+; X86-NEXT: cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT: sete %al
+; X86-NEXT: retl
+;
+; X64-LABEL: zext_eq_zero_i32:
+; X64: ## %bb.0:
+; X64-NEXT: xorl %eax, %eax
+; X64-NEXT: testl %edi, %edi
+; X64-NEXT: sete %al
+; X64-NEXT: retq
+ %cmp = icmp eq i32 %a, 0
+ %conv = zext i1 %cmp to i32
+ ret i32 %conv
+}
+
+define i32 @zext_and31_eq_zero_i32(i32 %a) {
+; X86-LABEL: zext_and31_eq_zero_i32:
+; X86: ## %bb.0:
+; X86-NEXT: xorl %eax, %eax
+; X86-NEXT: testb $31, {{[0-9]+}}(%esp)
+; X86-NEXT: sete %al
+; X86-NEXT: retl
+;
+; X64-NOBMI2-LABEL: zext_and31_eq_zero_i32:
+; X64-NOBMI2: ## %bb.0:
+; X64-NOBMI2-NEXT: xorl %eax, %eax
+; X64-NOBMI2-NEXT: testb $31, %dil
+; X64-NOBMI2-NEXT: sete %al
+; X64-NOBMI2-NEXT: retq
+;
+; X64-BMI2-LABEL: zext_and31_eq_zero_i32:
+; X64-BMI2: ## %bb.0:
+; X64-BMI2-NEXT: movl $1, %eax
+; X64-BMI2-NEXT: shrxl %edi, %eax, %eax
+; X64-BMI2-NEXT: retq
+ %and = and i32 %a, 31
+ %cmp = icmp eq i32 %and, 0
+ %conv = zext i1 %cmp to i32
+ ret i32 %conv
+}
+
+define i64 @zext_and63_eq_zero_i64(i64 %a) {
+; X86-LABEL: zext_and63_eq_zero_i64:
+; X86: ## %bb.0:
+; X86-NEXT: xorl %eax, %eax
+; X86-NEXT: testb $63, {{[0-9]+}}(%esp)
+; X86-NEXT: sete %al
+; X86-NEXT: xorl %edx, %edx
+; X86-NEXT: retl
+;
+; X64-NOBMI2-LABEL: zext_and63_eq_zero_i64:
+; X64-NOBMI2: ## %bb.0:
+; X64-NOBMI2-NEXT: xorl %eax, %eax
+; X64-NOBMI2-NEXT: testb $63, %dil
+; X64-NOBMI2-NEXT: sete %al
+; X64-NOBMI2-NEXT: retq
+;
+; X64-BMI2-LABEL: zext_and63_eq_zero_i64:
+; X64-BMI2: ## %bb.0:
+; X64-BMI2-NEXT: movl $1, %eax
+; X64-BMI2-NEXT: shrxq %rdi, %rax, %rax
+; X64-BMI2-NEXT: retq
+ %and = and i64 %a, 63
+ %cmp = icmp eq i64 %and, 0
+ %conv = zext i1 %cmp to i64
+ ret i64 %conv
+}
+
+define i32 @zext_and31_ne_zero_i32(i32 %a) {
+; X86-LABEL: zext_and31_ne_zero_i32:
+; X86: ## %bb.0:
+; X86-NEXT: xorl %eax, %eax
+; X86-NEXT: testb $31, {{[0-9]+}}(%esp)
+; X86-NEXT: setne %al
+; X86-NEXT: retl
+;
+; X64-LABEL: zext_and31_ne_zero_i32:
+; X64: ## %bb.0:
+; X64-NEXT: xorl %eax, %eax
+; X64-NEXT: testb $31, %dil
+; X64-NEXT: setne %al
+; X64-NEXT: retq
+ %and = and i32 %a, 31
+ %cmp = icmp ne i32 %and, 0
+ %conv = zext i1 %cmp to i32
+ ret i32 %conv
+}
>From 61cc7979d54771f6e002c3b5f5b266bdf9fca341 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=EC=9A=B1?=
<126692701+skku970412 at users.noreply.github.com>
Date: Tue, 7 Jul 2026 17:06:44 +0900
Subject: [PATCH 2/2] [X86] Address BMI2 zero-test review
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 21 ++++++---------------
1 file changed, 6 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 1a830690761df..96658f227b5c5 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -57315,23 +57315,14 @@ static SDValue combineExtSetcc(SDNode *N, SelectionDAG &DAG,
static SDValue combineZextSetccEqZeroToShift(SDNode *N, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
- if (!Subtarget.hasBMI2() || !Subtarget.is64Bit() ||
- N->getOpcode() != ISD::ZERO_EXTEND)
+ if (!Subtarget.hasBMI2() || N->getOpcode() != ISD::ZERO_EXTEND)
return SDValue();
- SDValue N0 = N->getOperand(0);
- if (N0.getOpcode() != ISD::SETCC || !N0.hasOneUse())
- return SDValue();
-
- ISD::CondCode CC = cast<CondCodeSDNode>(N0.getOperand(2))->get();
- if (CC != ISD::SETEQ)
- return SDValue();
-
- SDValue X = N0.getOperand(0);
- SDValue Y = N0.getOperand(1);
- if (isNullConstant(X))
- std::swap(X, Y);
- else if (!isNullConstant(Y))
+ using namespace SDPatternMatch;
+ SDValue X;
+ if (!sd_match(N->getOperand(0),
+ m_OneUse(m_c_SetCC(m_Value(X), m_Zero(),
+ m_SpecificCondCode(ISD::SETEQ)))))
return SDValue();
EVT ShiftVT = X.getValueType();
More information about the llvm-commits
mailing list