[llvm] [TargetLowering] Fold (a | b) ==/!= b -> (a & ~b) == /!= 0 when and-not exists (PR #145368)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 24 08:58:19 PDT 2025
https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/145368
>From 8393772ff8212b2071da44c7910ba80431a888c7 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Mon, 23 Jun 2025 12:38:38 -0400
Subject: [PATCH 1/2] Pre-commit test (NFC)
---
.../AArch64/aarch64-bitwisenot-fold.ll | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/llvm/test/CodeGen/AArch64/aarch64-bitwisenot-fold.ll b/llvm/test/CodeGen/AArch64/aarch64-bitwisenot-fold.ll
index 5fbf38b2560d4..28099a76fa34b 100644
--- a/llvm/test/CodeGen/AArch64/aarch64-bitwisenot-fold.ll
+++ b/llvm/test/CodeGen/AArch64/aarch64-bitwisenot-fold.ll
@@ -96,3 +96,29 @@ define i64 @andnot_sub_with_neg_i64(i64 %a0, i64 %a1) {
%and = and i64 %diff, %a0
ret i64 %and
}
+
+define i32 @and_not_select_eq(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: and_not_select_eq:
+; CHECK: // %bb.0:
+; CHECK-NEXT: orr w8, w1, w0
+; CHECK-NEXT: cmp w8, w0
+; CHECK-NEXT: csel w0, w0, w2, eq
+; CHECK-NEXT: ret
+ %or = or i32 %b, %a
+ %cmp = icmp eq i32 %or, %a
+ %a.c = select i1 %cmp, i32 %a, i32 %c
+ ret i32 %a.c
+}
+
+define i32 @and_not_select_ne(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: and_not_select_ne:
+; CHECK: // %bb.0:
+; CHECK-NEXT: orr w8, w1, w0
+; CHECK-NEXT: cmp w8, w0
+; CHECK-NEXT: csel w0, w0, w2, ne
+; CHECK-NEXT: ret
+ %or = or i32 %b, %a
+ %cmp = icmp ne i32 %or, %a
+ %a.c = select i1 %cmp, i32 %a, i32 %c
+ ret i32 %a.c
+}
>From 5e2253aa775e4d2d01b09044d5cbb6d43ba0e1ba Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Mon, 23 Jun 2025 13:22:51 -0400
Subject: [PATCH 2/2] [TargetLowering] Fold (a | b) ==/!= b -> (a & ~b) == /!=
0 when and-not exists
This is especially helpful for AArch64, which simplifies ands cmp to tst.
https://alive2.llvm.org/ce/z/LLgcJJ
Update TargetLowering.cpp
---
llvm/include/llvm/CodeGen/TargetLowering.h | 2 +
.../CodeGen/SelectionDAG/TargetLowering.cpp | 51 +++++++++++++++++++
.../AArch64/aarch64-bitwisenot-fold.ll | 6 +--
.../AArch64/switch-cases-to-branch-and.ll | 3 +-
4 files changed, 56 insertions(+), 6 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 727526055e592..ff2523b8a2517 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -5800,6 +5800,8 @@ class LLVM_ABI TargetLowering : public TargetLoweringBase {
private:
SDValue foldSetCCWithAnd(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond,
const SDLoc &DL, DAGCombinerInfo &DCI) const;
+ SDValue foldSetCCWithOr(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond,
+ const SDLoc &DL, DAGCombinerInfo &DCI) const;
SDValue foldSetCCWithBinOp(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond,
const SDLoc &DL, DAGCombinerInfo &DCI) const;
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 66717135c9adf..893ff3c5febd5 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -21,6 +21,7 @@
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/SDPatternMatch.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/IR/DataLayout.h"
@@ -4212,6 +4213,53 @@ SDValue TargetLowering::foldSetCCWithAnd(EVT VT, SDValue N0, SDValue N1,
return SDValue();
}
+/// This helper function of SimplifySetCC tries to optimize the comparison when
+/// either operand of the SetCC node is a bitwise-or instruction.
+/// For now, this just transforms (X | Y) ==/!= Y into X & ~Y ==/!= 0.
+SDValue TargetLowering::foldSetCCWithOr(EVT VT, SDValue N0, SDValue N1,
+ ISD::CondCode Cond, const SDLoc &DL,
+ DAGCombinerInfo &DCI) const {
+ if (N1.getOpcode() == ISD::OR && N0.getOpcode() != ISD::OR)
+ std::swap(N0, N1);
+
+ SelectionDAG &DAG = DCI.DAG;
+ EVT OpVT = N0.getValueType();
+ if (!N0.hasOneUse() || !OpVT.isInteger() ||
+ (Cond != ISD::SETEQ && Cond != ISD::SETNE))
+ return SDValue();
+
+ // Match these patterns in any of their permutations.
+ // (X | Y) == Y
+ // (X | Y) != Y
+ SDValue X, Y;
+ if (N0.getOperand(0) == N1) {
+ X = N0.getOperand(1);
+ Y = N0.getOperand(0);
+ } else if (N0.getOperand(1) == N1) {
+ X = N0.getOperand(0);
+ Y = N0.getOperand(1);
+ } else {
+ return SDValue();
+ }
+
+ if (hasAndNotCompare(Y)) {
+ // If the target supports an 'and-not' or 'and-complement' logic operation,
+ // try to use that to make a comparison operation more efficient.
+
+ // Bail out if the compare operand that we want to turn into a zero is
+ // already a zero (otherwise, infinite loop).
+ if (isNullConstant(Y))
+ return SDValue();
+
+ // Transform this into: X & ~Y == 0.
+ SDValue NotY = DAG.getNOT(SDLoc(Y), Y, OpVT);
+ SDValue NewAnd = DAG.getNode(ISD::AND, SDLoc(N0), OpVT, X, NotY);
+ return DAG.getSetCC(DL, VT, NewAnd, DAG.getConstant(0, DL, OpVT), Cond);
+ }
+
+ return SDValue();
+}
+
/// There are multiple IR patterns that could be checking whether certain
/// truncation of a signed number would be lossy or not. The pattern which is
/// best at IR level, may not lower optimally. Thus, we want to unfold it.
@@ -5507,6 +5555,9 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
if (SDValue V = foldSetCCWithAnd(VT, N0, N1, Cond, dl, DCI))
return V;
+
+ if (SDValue V = foldSetCCWithOr(VT, N0, N1, Cond, dl, DCI))
+ return V;
}
// Fold remainder of division by a constant.
diff --git a/llvm/test/CodeGen/AArch64/aarch64-bitwisenot-fold.ll b/llvm/test/CodeGen/AArch64/aarch64-bitwisenot-fold.ll
index 28099a76fa34b..2c8a4b5f6be53 100644
--- a/llvm/test/CodeGen/AArch64/aarch64-bitwisenot-fold.ll
+++ b/llvm/test/CodeGen/AArch64/aarch64-bitwisenot-fold.ll
@@ -100,8 +100,7 @@ define i64 @andnot_sub_with_neg_i64(i64 %a0, i64 %a1) {
define i32 @and_not_select_eq(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: and_not_select_eq:
; CHECK: // %bb.0:
-; CHECK-NEXT: orr w8, w1, w0
-; CHECK-NEXT: cmp w8, w0
+; CHECK-NEXT: bics wzr, w1, w0
; CHECK-NEXT: csel w0, w0, w2, eq
; CHECK-NEXT: ret
%or = or i32 %b, %a
@@ -113,8 +112,7 @@ define i32 @and_not_select_eq(i32 %a, i32 %b, i32 %c) {
define i32 @and_not_select_ne(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: and_not_select_ne:
; CHECK: // %bb.0:
-; CHECK-NEXT: orr w8, w1, w0
-; CHECK-NEXT: cmp w8, w0
+; CHECK-NEXT: bics wzr, w1, w0
; CHECK-NEXT: csel w0, w0, w2, ne
; CHECK-NEXT: ret
%or = or i32 %b, %a
diff --git a/llvm/test/CodeGen/AArch64/switch-cases-to-branch-and.ll b/llvm/test/CodeGen/AArch64/switch-cases-to-branch-and.ll
index 4d36a003cbfe4..e99ba4843c452 100644
--- a/llvm/test/CodeGen/AArch64/switch-cases-to-branch-and.ll
+++ b/llvm/test/CodeGen/AArch64/switch-cases-to-branch-and.ll
@@ -569,8 +569,7 @@ define void @test_successor_with_loop_phi(ptr %A, ptr %B) {
; CHECK-NEXT: ldr w8, [x0]
; CHECK-NEXT: str wzr, [x0]
; CHECK-NEXT: mov x0, x1
-; CHECK-NEXT: orr w8, w8, #0x4
-; CHECK-NEXT: cmp w8, #4
+; CHECK-NEXT: tst w8, #0xfffffffb
; CHECK-NEXT: b.eq LBB7_1
; CHECK-NEXT: ; %bb.2: ; %exit
; CHECK-NEXT: ret
More information about the llvm-commits
mailing list