-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[RISCV] Efficiently lower (select %cond, andn (f, x), f) using zicond #147369
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@llvm/pr-subscribers-backend-risc-v Author: Ryan Buchner (bababuck) ChangesThe following case is now optimized: Full diff: https://github.com/llvm/llvm-project/pull/147369.diff 2 Files Affected:
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index dfb003a9cb1c1..80b5db51f20a1 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -9064,18 +9064,51 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
if (isNullConstant(TrueV))
return DAG.getNode(RISCVISD::CZERO_NEZ, DL, VT, FalseV, CondV);
+ // Check to see if a given operation is a 'NOT', if so return the negated
+ // operand
+ auto getNotOperand = [](const SDValue &Op) -> std::optional<const SDValue> {
+ using namespace llvm::SDPatternMatch;
+ SDValue Xor;
+ if (sd_match(Op, m_OneUse(m_Not(m_Value(Xor))))) {
+ return std::optional<const SDValue>{Xor};
+ }
+ return std::nullopt;
+ };
// (select c, (and f, x), f) -> (or (and f, x), (czero_nez f, c))
+ // (select c, (and f, ~x), f) -> (andn f, (czero_eqz x, c))
if (TrueV.getOpcode() == ISD::AND &&
- (TrueV.getOperand(0) == FalseV || TrueV.getOperand(1) == FalseV))
+ (TrueV.getOperand(0) == FalseV || TrueV.getOperand(1) == FalseV)) {
+ auto NotOperand = (TrueV.getOperand(0) == FalseV)
+ ? getNotOperand(TrueV.getOperand(1))
+ : getNotOperand(TrueV.getOperand(0));
+ if (NotOperand) {
+ SDValue CMOV =
+ DAG.getNode(RISCVISD::CZERO_EQZ, DL, VT, *NotOperand, CondV);
+ SDValue NOT = DAG.getNOT(DL, CMOV, VT);
+ return DAG.getNode(ISD::AND, DL, VT, FalseV, NOT);
+ }
return DAG.getNode(
ISD::OR, DL, VT, TrueV,
DAG.getNode(RISCVISD::CZERO_NEZ, DL, VT, FalseV, CondV));
+ }
+
// (select c, t, (and t, x)) -> (or (czero_eqz t, c), (and t, x))
+ // (select c, t, (and t, ~x)) -> (andn t, (czero_nez x, c))
if (FalseV.getOpcode() == ISD::AND &&
- (FalseV.getOperand(0) == TrueV || FalseV.getOperand(1) == TrueV))
+ (FalseV.getOperand(0) == TrueV || FalseV.getOperand(1) == TrueV)) {
+ auto NotOperand = (FalseV.getOperand(0) == TrueV)
+ ? getNotOperand(FalseV.getOperand(1))
+ : getNotOperand(FalseV.getOperand(0));
+ if (NotOperand) {
+ SDValue CMOV =
+ DAG.getNode(RISCVISD::CZERO_NEZ, DL, VT, *NotOperand, CondV);
+ SDValue NOT = DAG.getNOT(DL, CMOV, VT);
+ return DAG.getNode(ISD::AND, DL, VT, TrueV, NOT);
+ }
return DAG.getNode(
ISD::OR, DL, VT, FalseV,
DAG.getNode(RISCVISD::CZERO_EQZ, DL, VT, TrueV, CondV));
+ }
// Try some other optimizations before falling back to generic lowering.
if (SDValue V = combineSelectToBinOp(Op.getNode(), DAG, Subtarget))
diff --git a/llvm/test/CodeGen/RISCV/zicond-opts.ll b/llvm/test/CodeGen/RISCV/zicond-opts.ll
index 35b06c4f4fb41..a16145d15db81 100644
--- a/llvm/test/CodeGen/RISCV/zicond-opts.ll
+++ b/llvm/test/CodeGen/RISCV/zicond-opts.ll
@@ -233,9 +233,8 @@ define i64 @test_inv_and_nez(i64 %f, i64 %x, i1 %cond) {
; RV64ZICOND-LABEL: test_inv_and_nez:
; RV64ZICOND: # %bb.0:
; RV64ZICOND-NEXT: andi a2, a2, 1
-; RV64ZICOND-NEXT: andn a1, a0, a1
-; RV64ZICOND-NEXT: czero.nez a0, a0, a2
-; RV64ZICOND-NEXT: or a0, a1, a0
+; RV64ZICOND-NEXT: czero.eqz a1, a1, a2
+; RV64ZICOND-NEXT: andn a0, a0, a1
; RV64ZICOND-NEXT: ret
%5 = xor i64 %x, -1
%6 = select i1 %cond, i64 %5, i64 -1
@@ -258,9 +257,8 @@ define i64 @test_inv_and_eqz(i64 %f, i64 %x, i1 %cond) {
; RV64ZICOND-LABEL: test_inv_and_eqz:
; RV64ZICOND: # %bb.0:
; RV64ZICOND-NEXT: andi a2, a2, 1
-; RV64ZICOND-NEXT: andn a1, a0, a1
-; RV64ZICOND-NEXT: czero.eqz a0, a0, a2
-; RV64ZICOND-NEXT: or a0, a1, a0
+; RV64ZICOND-NEXT: czero.nez a1, a1, a2
+; RV64ZICOND-NEXT: andn a0, a0, a1
; RV64ZICOND-NEXT: ret
%5 = xor i64 %x, -1
%6 = select i1 %cond, i64 -1, i64 %5
|
… extension The following case is now optimized: (select c, (and f, ~x), f) -> (andn f, (czero_eqz x, c))
a9d6c50 to
f5031ab
Compare
|
Don't force push unless necessary. Use fixup commits. The final push will be done with squash so any messy history in the PR won't matter. |
topperc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/55/builds/13976 Here is the relevant piece of the build log for the reference |
The following case is now optimized:
(select c, (and f, ~x), f) -> (andn f, (czero_eqz x, c))