Skip to content

Commit 0798c6a

Browse files
committed
[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
1 parent d855301 commit 0798c6a

File tree

4 files changed

+45
-6
lines changed

4 files changed

+45
-6
lines changed

llvm/include/llvm/CodeGen/TargetLowering.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5800,6 +5800,8 @@ class LLVM_ABI TargetLowering : public TargetLoweringBase {
58005800
private:
58015801
SDValue foldSetCCWithAnd(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond,
58025802
const SDLoc &DL, DAGCombinerInfo &DCI) const;
5803+
SDValue foldSetCCWithOr(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond,
5804+
const SDLoc &DL, DAGCombinerInfo &DCI) const;
58035805
SDValue foldSetCCWithBinOp(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond,
58045806
const SDLoc &DL, DAGCombinerInfo &DCI) const;
58055807

llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4212,6 +4212,43 @@ SDValue TargetLowering::foldSetCCWithAnd(EVT VT, SDValue N0, SDValue N1,
42124212
return SDValue();
42134213
}
42144214

4215+
/// This helper function of SimplifySetCC tries to optimize the comparison when
4216+
/// either operand of the SetCC node is a bitwise-or instruction.
4217+
/// For now, this just transforms (X | Y) ==/!= Y into X & ~Y ==/!= 0.
4218+
SDValue TargetLowering::foldSetCCWithOr(EVT VT, SDValue N0, SDValue N1,
4219+
ISD::CondCode Cond, const SDLoc &DL,
4220+
DAGCombinerInfo &DCI) const {
4221+
if (N1.getOpcode() == ISD::OR && N0.getOpcode() != ISD::OR)
4222+
std::swap(N0, N1);
4223+
4224+
SelectionDAG &DAG = DCI.DAG;
4225+
EVT OpVT = N0.getValueType();
4226+
if (!N0.hasOneUse() || !OpVT.isInteger() ||
4227+
(Cond != ISD::SETEQ && Cond != ISD::SETNE))
4228+
return SDValue();
4229+
4230+
// (X | Y) == Y
4231+
// (X | Y) != Y
4232+
SDValue X;
4233+
if (sd_match(N0, m_c_Or(m_Value(X), m_Specific(N1))) &&
4234+
hasAndNotCompare(N1)) {
4235+
// If the target supports an 'and-not' or 'and-complement' logic operation,
4236+
// try to use that to make a comparison operation more efficient.
4237+
4238+
// Bail out if the compare operand that we want to turn into a zero is
4239+
// already a zero (otherwise, infinite loop).
4240+
if (isNullConstant(N1))
4241+
return SDValue();
4242+
4243+
// Transform this into: X & ~Y ==/!= 0.
4244+
SDValue NotY = DAG.getNOT(SDLoc(N1), N1, OpVT);
4245+
SDValue NewAnd = DAG.getNode(ISD::AND, SDLoc(N0), OpVT, X, NotY);
4246+
return DAG.getSetCC(DL, VT, NewAnd, DAG.getConstant(0, DL, OpVT), Cond);
4247+
}
4248+
4249+
return SDValue();
4250+
}
4251+
42154252
/// There are multiple IR patterns that could be checking whether certain
42164253
/// truncation of a signed number would be lossy or not. The pattern which is
42174254
/// best at IR level, may not lower optimally. Thus, we want to unfold it.
@@ -5507,6 +5544,9 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
55075544

55085545
if (SDValue V = foldSetCCWithAnd(VT, N0, N1, Cond, dl, DCI))
55095546
return V;
5547+
5548+
if (SDValue V = foldSetCCWithOr(VT, N0, N1, Cond, dl, DCI))
5549+
return V;
55105550
}
55115551

55125552
// Fold remainder of division by a constant.

llvm/test/CodeGen/AArch64/aarch64-bitwisenot-fold.ll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ define i64 @andnot_sub_with_neg_i64(i64 %a0, i64 %a1) {
100100
define i32 @and_not_select_eq(i32 %a, i32 %b, i32 %c) {
101101
; CHECK-LABEL: and_not_select_eq:
102102
; CHECK: // %bb.0:
103-
; CHECK-NEXT: orr w8, w1, w0
104-
; CHECK-NEXT: cmp w8, w0
103+
; CHECK-NEXT: bics wzr, w1, w0
105104
; CHECK-NEXT: csel w0, w0, w2, eq
106105
; CHECK-NEXT: ret
107106
%or = or i32 %b, %a
@@ -113,8 +112,7 @@ define i32 @and_not_select_eq(i32 %a, i32 %b, i32 %c) {
113112
define i32 @and_not_select_ne(i32 %a, i32 %b, i32 %c) {
114113
; CHECK-LABEL: and_not_select_ne:
115114
; CHECK: // %bb.0:
116-
; CHECK-NEXT: orr w8, w1, w0
117-
; CHECK-NEXT: cmp w8, w0
115+
; CHECK-NEXT: bics wzr, w1, w0
118116
; CHECK-NEXT: csel w0, w0, w2, ne
119117
; CHECK-NEXT: ret
120118
%or = or i32 %b, %a

llvm/test/CodeGen/AArch64/switch-cases-to-branch-and.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -569,8 +569,7 @@ define void @test_successor_with_loop_phi(ptr %A, ptr %B) {
569569
; CHECK-NEXT: ldr w8, [x0]
570570
; CHECK-NEXT: str wzr, [x0]
571571
; CHECK-NEXT: mov x0, x1
572-
; CHECK-NEXT: orr w8, w8, #0x4
573-
; CHECK-NEXT: cmp w8, #4
572+
; CHECK-NEXT: tst w8, #0xfffffffb
574573
; CHECK-NEXT: b.eq LBB7_1
575574
; CHECK-NEXT: ; %bb.2: ; %exit
576575
; CHECK-NEXT: ret

0 commit comments

Comments
 (0)