[llvm-branch-commits] [llvm] [AMDGPU] Fold AND of any-extended SGPR booleans to select (PR #230701)
Alan Li via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Oct 9 16:08:52 PDT 2026
https://github.com/lialan created https://github.com/llvm/llvm-project/pull/230701
## Issue
Demanded-bits simplification can turn a boolean sign extension into `ANY_EXTEND` before the target `AND` combine, causing the existing AND-to-select fold to miss.
## Fix
Extend the i32 combine to accept `ANY_EXTEND` of an SGPR boolean on either operand. Its unspecified high bits can be chosen to match sign extension, allowing `and x, (anyext cc)` to fold to `select cc, x, 0`.
## Validation
On AMDGPU, for a sign-extended condition `AND`ed with a logical right shift by 31, this removes an extra `v_and_b32`. Add regression coverage for both operand orders and zero extension. Existing test RUN lines are unchanged.
>From 807079e0fd0f7d2cd03ccb4561da244cfe1b3c41 Mon Sep 17 00:00:00 2001
From: Alan Li <me at alanli.org>
Date: Fri, 9 Oct 2026 14:41:11 -0700
Subject: [PATCH] fix(AMDGPU): fold AND of any-extended booleans
Demanded-bits simplification can turn a boolean sign extension into an
any extension before the target AND combine. Choose sign extension for
the undefined high bits so the AND still folds to a select.
Cover reduced demand, swapped operands, and zero extension. Restore the
fold in setcc-multiple-use after symmetric demanded-bits simplification.
---
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 18 +++++---
.../CodeGen/AMDGPU/combine-and-sext-bool.ll | 46 +++++++++++++++++++
.../test/CodeGen/AMDGPU/setcc-multiple-use.ll | 7 ++-
3 files changed, 60 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 7f2784726c4760..33bf38f3792bdb 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -15121,14 +15121,18 @@ SDValue SITargetLowering::performAndCombine(SDNode *N,
}
}
- if (VT == MVT::i32 && (RHS.getOpcode() == ISD::SIGN_EXTEND ||
- LHS.getOpcode() == ISD::SIGN_EXTEND)) {
- // and x, (sext cc from i1) => select cc, x, 0
- if (RHS.getOpcode() != ISD::SIGN_EXTEND)
+ auto IsBoolExt = [](SDValue V) {
+ return (V.getOpcode() == ISD::SIGN_EXTEND ||
+ V.getOpcode() == ISD::ANY_EXTEND) &&
+ isBoolSGPR(V.getOperand(0));
+ };
+ if (VT == MVT::i32 && (IsBoolExt(RHS) || IsBoolExt(LHS))) {
+ // and x, (sext/anyext cc from i1) => select cc, x, 0
+ // Any-extended bits can be chosen to match sign extension.
+ if (!IsBoolExt(RHS))
std::swap(LHS, RHS);
- if (isBoolSGPR(RHS.getOperand(0)))
- return DAG.getSelect(SDLoc(N), MVT::i32, RHS.getOperand(0), LHS,
- DAG.getConstant(0, SDLoc(N), MVT::i32));
+ return DAG.getSelect(SDLoc(N), MVT::i32, RHS.getOperand(0), LHS,
+ DAG.getConstant(0, SDLoc(N), MVT::i32));
}
// and (op x, c1), (op y, c2) -> perm x, y, permute_mask(c1, c2)
diff --git a/llvm/test/CodeGen/AMDGPU/combine-and-sext-bool.ll b/llvm/test/CodeGen/AMDGPU/combine-and-sext-bool.ll
index c18d2234470ae6..33c03533ac766a 100644
--- a/llvm/test/CodeGen/AMDGPU/combine-and-sext-bool.ll
+++ b/llvm/test/CodeGen/AMDGPU/combine-and-sext-bool.ll
@@ -149,6 +149,52 @@ define i32 @and_sext_bool_umul_w_overflow(i32 %x, i32 %y) {
ret i32 %and
}
+; Only bit 0 of the sext is demanded, so it becomes an anyext before the
+; target combine. The AND should still fold to a select.
+define i32 @and_anyext_bool(i32 %x, i32 %y) {
+; GCN-LABEL: and_anyext_bool:
+; GCN: ; %bb.0:
+; GCN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GCN-NEXT: v_lshrrev_b32_e32 v1, 31, v1
+; GCN-NEXT: v_cmp_eq_u32_e32 vcc, 0, v0
+; GCN-NEXT: v_cndmask_b32_e32 v0, 0, v1, vcc
+; GCN-NEXT: s_setpc_b64 s[30:31]
+ %cmp = icmp eq i32 %x, 0
+ %ext = sext i1 %cmp to i32
+ %bit = lshr i32 %y, 31
+ %and = and i32 %ext, %bit
+ ret i32 %and
+}
+
+define i32 @and_anyext_bool_commuted(i32 %x, i32 %y) {
+; GCN-LABEL: and_anyext_bool_commuted:
+; GCN: ; %bb.0:
+; GCN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GCN-NEXT: v_lshrrev_b32_e32 v1, 31, v1
+; GCN-NEXT: v_cmp_eq_u32_e32 vcc, 0, v0
+; GCN-NEXT: v_cndmask_b32_e32 v0, 0, v1, vcc
+; GCN-NEXT: s_setpc_b64 s[30:31]
+ %cmp = icmp eq i32 %x, 0
+ %ext = sext i1 %cmp to i32
+ %bit = lshr i32 %y, 31
+ %and = and i32 %bit, %ext
+ ret i32 %and
+}
+
+; A zext must clear the high bits even when the condition is true.
+define i32 @and_zext_bool(i32 %x, i32 %y) {
+; GCN-LABEL: and_zext_bool:
+; GCN: ; %bb.0:
+; GCN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GCN-NEXT: v_cmp_eq_u32_e32 vcc, 0, v0
+; GCN-NEXT: v_cndmask_b32_e64 v0, 0, 1, vcc
+; GCN-NEXT: v_and_b32_e32 v0, v0, v1
+; GCN-NEXT: s_setpc_b64 s[30:31]
+ %cmp = icmp eq i32 %x, 0
+ %ext = zext i1 %cmp to i32
+ %and = and i32 %ext, %y
+ ret i32 %and
+}
declare i32 @llvm.amdgcn.workitem.id.x() #0
diff --git a/llvm/test/CodeGen/AMDGPU/setcc-multiple-use.ll b/llvm/test/CodeGen/AMDGPU/setcc-multiple-use.ll
index cda1c07d058866..3fbeecfbf92133 100644
--- a/llvm/test/CodeGen/AMDGPU/setcc-multiple-use.ll
+++ b/llvm/test/CodeGen/AMDGPU/setcc-multiple-use.ll
@@ -14,11 +14,10 @@ define i32 @f() {
; CHECK-NEXT: v_mov_b32_e32 v0, 0
; CHECK-NEXT: ds_read_b32 v0, v0
; CHECK-NEXT: s_waitcnt lgkmcnt(0)
-; CHECK-NEXT: v_cmp_ne_u32_e32 vcc_lo, 0, v0
-; CHECK-NEXT: v_cndmask_b32_e64 v1, 0, 1, vcc_lo
; CHECK-NEXT: v_cmp_eq_u32_e32 vcc_lo, 0, v0
-; CHECK-NEXT: v_cndmask_b32_e64 v0, 0, 1, vcc_lo
-; CHECK-NEXT: v_and_b32_e32 v0, v0, v1
+; CHECK-NEXT: v_cndmask_b32_e64 v1, 0, 1, vcc_lo
+; CHECK-NEXT: v_cmp_ne_u32_e32 vcc_lo, 0, v0
+; CHECK-NEXT: v_cndmask_b32_e32 v0, 0, v1, vcc_lo
; CHECK-NEXT: s_setpc_b64 s[30:31]
bb:
%i = load i32, ptr addrspace(3) zeroinitializer, align 16
More information about the llvm-branch-commits
mailing list