[llvm] 8c74c54 - Make `(and/or (icmp eq/ne A, C0), (icmp eq/ne A, C1))` where `IsPow(dif(C0,C1))` work for more patterns.
Noah Goldstein via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 24 13:22:34 PST 2023
Author: Noah Goldstein
Date: 2023-02-24T15:22:09-06:00
New Revision: 8c74c5402f6dd400163fed7c3b39a376fa9e9dc1
URL: https://github.com/llvm/llvm-project/commit/8c74c5402f6dd400163fed7c3b39a376fa9e9dc1
DIFF: https://github.com/llvm/llvm-project/commit/8c74c5402f6dd400163fed7c3b39a376fa9e9dc1.diff
LOG: Make `(and/or (icmp eq/ne A,C0), (icmp eq/ne A,C1))` where `IsPow(dif(C0,C1))` work for more patterns.
`(and/or (icmp eq/ne A,C0), (icmp eq/ne A,C1))` can be lowered to
`(icmp eq/ne (and (sub A, (smin C0, C1)), (not (sub (smax C0, C1), (smin C0, C1)))), 0)`
generically if `(sub (smax C0, C1), (smin C0,C1))` is a power of 2.
This covers the existing case of `(and/or (icmp eq/ne A, C_Pow2),(icmp eq/ne A, -C_Pow2))`
as well as other cases.
Alive2 Links:
EQ: https://alive2.llvm.org/ce/z/mLJiUW
NE: https://alive2.llvm.org/ce/z/TKnzUr
Differential Revision: https://reviews.llvm.org/D144283
Added:
Modified:
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
llvm/test/CodeGen/X86/icmp-pow2-diff.ll
llvm/test/CodeGen/X86/setcc-logic.ll
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index e25426a2afc58..f610e1c96a273 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -5907,8 +5907,8 @@ static SDValue foldAndOrOfSETCC(SDNode *LogicOp, SelectionDAG &DAG) {
SDValue LHS1 = LHS->getOperand(1);
SDValue RHS1 = RHS->getOperand(1);
- // TODO: We don't actually need a splat here, for vectors we just need
- // LaneLHS[N] == -LaneRHS[N];
+ // TODO: We don't actually need a splat here, for vectors we just need the
+ // invariants to hold for each element.
auto *LHS1C = isConstOrConstSplat(LHS1);
auto *RHS1C = isConstOrConstSplat(RHS1);
@@ -5919,15 +5919,16 @@ static SDValue foldAndOrOfSETCC(SDNode *LogicOp, SelectionDAG &DAG) {
if (CCL == CCR &&
CCL == (LogicOp->getOpcode() == ISD::AND ? ISD::SETNE : ISD::SETEQ) &&
LHS0 == RHS0 && LHS1C && RHS1C && OpVT.isInteger() && LHS.hasOneUse() &&
- RHS.hasOneUse() && LHS1C->getAPIntValue() == (-RHS1C->getAPIntValue())) {
+ RHS.hasOneUse()) {
+ const APInt &APLhs = LHS1C->getAPIntValue();
+ const APInt &APRhs = RHS1C->getAPIntValue();
// Preference is to use ISD::ABS or we already have an ISD::ABS (in which
// case this is just a compare).
- if (TargetPreference == AndOrSETCCFoldKind::ABS ||
- DAG.doesNodeExist(ISD::ABS, DAG.getVTList(OpVT), {LHS0})) {
- APInt C = LHS1C->getAPIntValue();
- if (C.isNegative())
- C = RHS1C->getAPIntValue();
+ if (APLhs == (-APRhs) &&
+ (TargetPreference == AndOrSETCCFoldKind::ABS ||
+ DAG.doesNodeExist(ISD::ABS, DAG.getVTList(OpVT), {LHS0}))) {
+ const APInt &C = APLhs.isNegative() ? APRhs : APLhs;
// (icmp eq A, C) | (icmp eq A, -C)
// -> (icmp eq Abs(A), C)
// (icmp ne A, C) & (icmp ne A, -C)
@@ -5936,23 +5937,20 @@ static SDValue foldAndOrOfSETCC(SDNode *LogicOp, SelectionDAG &DAG) {
return DAG.getNode(ISD::SETCC, DL, VT, AbsOp,
DAG.getConstant(C, DL, OpVT), LHS.getOperand(2));
} else if (TargetPreference == AndOrSETCCFoldKind::AddAnd) {
- // With C as a power of 2 and C != 0 and C != INT_MIN:
- // (icmp eq A, C) | (icmp eq A, -C)
- // -> (icmp eq and(add(A, C), ~(C + C)), 0)
- // (icmp ne A, C) & (icmp ne A, -C)w
- // -> (icmp ne and(add(A, C), ~(C + C)), 0)
- const ConstantSDNode *Pow2 = nullptr;
- if (LHS1C->getAPIntValue().isPowerOf2())
- Pow2 = LHS1C;
- else if (RHS1C->getAPIntValue().isPowerOf2())
- Pow2 = RHS1C;
- // isPowerOf2 is only for non-zero powers of 2.
- if (Pow2 != nullptr && !Pow2->getAPIntValue().isMinSignedValue()) {
- const APInt &C = Pow2->getAPIntValue();
- SDValue AddOp =
- DAG.getNode(ISD::ADD, DL, OpVT, LHS0, DAG.getConstant(C, DL, OpVT));
+ // A == C0 | A == C1
+ // IF IsPow2(smax(C0, C1)-smin(C0, C1))
+ // -> ((A - smin(C0, C1)) & ~(smax(C0, C1)-smin(C0, C1))) == 0
+ // A != C0 & A != C1
+ // IF IsPow2(smax(C0, C1)-smin(C0, C1))
+ // -> ((A - smin(C0, C1)) & ~(smax(C0, C1)-smin(C0, C1))) != 0
+ const APInt &MaxC = APIntOps::smax(APRhs, APLhs);
+ const APInt &MinC = APIntOps::smin(APRhs, APLhs);
+ APInt Dif = MaxC - MinC;
+ if (!Dif.isZero() && Dif.isPowerOf2()) {
+ SDValue AddOp = DAG.getNode(ISD::ADD, DL, OpVT, LHS0,
+ DAG.getConstant(-MinC, DL, OpVT));
SDValue AndOp = DAG.getNode(ISD::AND, DL, OpVT, AddOp,
- DAG.getConstant(~(C + C), DL, OpVT));
+ DAG.getConstant(~Dif, DL, OpVT));
return DAG.getNode(ISD::SETCC, DL, VT, AndOp,
DAG.getConstant(0, DL, OpVT), LHS.getOperand(2));
}
diff --git a/llvm/test/CodeGen/X86/icmp-pow2-
diff .ll b/llvm/test/CodeGen/X86/icmp-pow2-
diff .ll
index 0ac4286c01c3d..5c7c3e9cff5b1 100644
--- a/llvm/test/CodeGen/X86/icmp-pow2-
diff .ll
+++ b/llvm/test/CodeGen/X86/icmp-pow2-
diff .ll
@@ -311,12 +311,9 @@ define i1 @andnot_ne_i32(i32 %x) nounwind {
define i1 @addand_ne_i16(i16 %x) nounwind {
; CHECK-LABEL: addand_ne_i16:
; CHECK: # %bb.0:
-; CHECK-NEXT: cmpw $-3, %di
-; CHECK-NEXT: setne %cl
-; CHECK-NEXT: movzwl %di, %eax
-; CHECK-NEXT: cmpl $16381, %eax # imm = 0x3FFD
+; CHECK-NEXT: addl $3, %edi
+; CHECK-NEXT: testl $49151, %edi # imm = 0xBFFF
; CHECK-NEXT: setne %al
-; CHECK-NEXT: andb %cl, %al
; CHECK-NEXT: retq
%cmp1 = icmp ne i16 %x, -3
%cmp2 = icmp ne i16 %x, 16381
@@ -362,11 +359,9 @@ define <8 x i1> @addand_ne_v8i16_fail(<8 x i16> %x) nounwind {
define i1 @addand_eq_i32(i32 %x) nounwind {
; CHECK-LABEL: addand_eq_i32:
; CHECK: # %bb.0:
-; CHECK-NEXT: cmpl $-1, %edi
-; CHECK-NEXT: sete %cl
-; CHECK-NEXT: cmpl $7, %edi
+; CHECK-NEXT: incl %edi
+; CHECK-NEXT: testl $-9, %edi
; CHECK-NEXT: sete %al
-; CHECK-NEXT: orb %cl, %al
; CHECK-NEXT: retq
%cmp1 = icmp eq i32 %x, -1
%cmp2 = icmp eq i32 %x, 7
@@ -393,11 +388,9 @@ define i1 @addand_eq_i8_fail_abs_p2_minmax_not(i8 %x) nounwind {
define i1 @addand_ne_i8(i8 %x) nounwind {
; CHECK-LABEL: addand_ne_i8:
; CHECK: # %bb.0:
-; CHECK-NEXT: cmpb $59, %dil
-; CHECK-NEXT: setne %cl
-; CHECK-NEXT: cmpb $-5, %dil
+; CHECK-NEXT: addb $5, %dil
+; CHECK-NEXT: testb $-65, %dil
; CHECK-NEXT: setne %al
-; CHECK-NEXT: andb %cl, %al
; CHECK-NEXT: retq
%cmp1 = icmp ne i8 %x, 59
%cmp2 = icmp ne i8 %x, -5
@@ -424,11 +417,9 @@ define i1 @addand_eq_i64_fail_non_p2_dif(i64 %x) nounwind {
define i1 @addand_eq_i64(i64 %x) nounwind {
; CHECK-LABEL: addand_eq_i64:
; CHECK: # %bb.0:
-; CHECK-NEXT: cmpq $768, %rdi # imm = 0x300
-; CHECK-NEXT: setne %cl
-; CHECK-NEXT: cmpq $-256, %rdi
+; CHECK-NEXT: addq $256, %rdi # imm = 0x100
+; CHECK-NEXT: testq $-1025, %rdi # imm = 0xFBFF
; CHECK-NEXT: setne %al
-; CHECK-NEXT: andb %cl, %al
; CHECK-NEXT: retq
%cmp1 = icmp ne i64 %x, 768
%cmp2 = icmp ne i64 %x, -256
diff --git a/llvm/test/CodeGen/X86/setcc-logic.ll b/llvm/test/CodeGen/X86/setcc-logic.ll
index 1a26b9ae8cadf..baad9698472a7 100644
--- a/llvm/test/CodeGen/X86/setcc-logic.ll
+++ b/llvm/test/CodeGen/X86/setcc-logic.ll
@@ -456,8 +456,8 @@ define zeroext i1 @ne_neg1_and_ne_zero(i64 %x) nounwind {
; CHECK-LABEL: ne_neg1_and_ne_zero:
; CHECK: # %bb.0:
; CHECK-NEXT: incq %rdi
-; CHECK-NEXT: cmpq $2, %rdi
-; CHECK-NEXT: setae %al
+; CHECK-NEXT: testq $-2, %rdi
+; CHECK-NEXT: setne %al
; CHECK-NEXT: retq
%cmp1 = icmp ne i64 %x, -1
%cmp2 = icmp ne i64 %x, 0
More information about the llvm-commits
mailing list