[llvm] d018958 - [RISCV] Fold binary op into select if profitable.
Mikhail Gudim via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 12 11:19:25 PDT 2023
Author: Mikhail Gudim
Date: 2023-06-12T14:19:12-04:00
New Revision: d0189584631e587279ee5f0af5feb94d8045bb31
URL: https://github.com/llvm/llvm-project/commit/d0189584631e587279ee5f0af5feb94d8045bb31
DIFF: https://github.com/llvm/llvm-project/commit/d0189584631e587279ee5f0af5feb94d8045bb31.diff
LOG: [RISCV] Fold binary op into select if profitable.
Consider the following pattern `binOp (select cond, x, c0), c1`.
Where `c0` and `c1` are constants.
We can transform it to `select cond, binOp(x, c1), binOp(c0, c1)`.
If `binOp(c0, c1)` ends up being `0` or `-1` we can turn the select into
a more profitable sequence.
Added:
llvm/test/CodeGen/RISCV/fold-binop-into-select.ll
Modified:
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 6abbcb6d19997..4903fb8f8ef8f 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -5606,6 +5606,65 @@ static SDValue combineSelectToBinOp(SDNode *N, SelectionDAG &DAG,
return SDValue();
}
+// Transform `binOp (select cond, x, c0), c1` where `c0` and `c1` are constants
+// into `select cond, binOp(x, c1), binOp(c0, c1)` if profitable.
+// For now we only consider transformation profitable if `binOp(c0, c1)` ends up
+// being `0` or `-1`. In such cases we can replace `select` with `and`.
+// TODO: Should we also do this if `binOp(c0, c1)` is cheaper to materialize
+// than `c0`?
+static SDValue
+foldBinOpIntoSelectIfProfitable(SDNode *BO, SelectionDAG &DAG,
+ const RISCVSubtarget &Subtarget) {
+ if (Subtarget.hasShortForwardBranchOpt())
+ return SDValue();
+
+ unsigned SelOpNo = 0;
+ SDValue Sel = BO->getOperand(0);
+ if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse()) {
+ SelOpNo = 1;
+ Sel = BO->getOperand(1);
+ }
+
+ if (Sel.getOpcode() != ISD::SELECT || !Sel.hasOneUse())
+ return SDValue();
+
+ unsigned ConstSelOpNo = 1;
+ unsigned OtherSelOpNo = 2;
+ SDValue ConstSelOp = Sel->getOperand(1);
+ ConstantSDNode *ConstSelOpNode = dyn_cast<ConstantSDNode>(ConstSelOp);
+ if (!ConstSelOpNode) {
+ ConstSelOpNo = 2;
+ OtherSelOpNo = 1;
+ ConstSelOp = Sel->getOperand(2);
+ ConstSelOpNode = dyn_cast<ConstantSDNode>(ConstSelOp);
+ }
+ if (!ConstSelOpNode)
+ return SDValue();
+ if (!ConstSelOpNode || ConstSelOpNode->isOpaque())
+ return SDValue();
+
+ SDValue ConstBinOp = BO->getOperand(SelOpNo ^ 1);
+ ConstantSDNode *ConstBinOpNode = dyn_cast<ConstantSDNode>(ConstBinOp);
+ if (!ConstBinOpNode || ConstBinOpNode->isOpaque())
+ return SDValue();
+
+ SDLoc DL(Sel);
+ EVT VT = BO->getValueType(0);
+
+ SDValue NewConstOp = DAG.FoldConstantArithmetic(BO->getOpcode(), DL, VT,
+ {ConstSelOp, ConstBinOp});
+ const APInt &NewConstAPInt =
+ cast<ConstantSDNode>(NewConstOp)->getAPIntValue();
+ if (!NewConstAPInt.isZero() && !NewConstAPInt.isAllOnes())
+ return SDValue();
+
+ SDValue NewNonConstOp = DAG.getNode(
+ BO->getOpcode(), DL, VT, Sel->getOperand(OtherSelOpNo), ConstBinOp);
+ SDValue NewT = (ConstSelOpNo == 1) ? NewConstOp : NewNonConstOp;
+ SDValue NewF = (ConstSelOpNo == 1) ? NewNonConstOp : NewConstOp;
+ return DAG.getSelect(DL, VT, Sel.getOperand(0), NewT, NewF);
+}
+
SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
SDValue CondV = Op.getOperand(0);
SDValue TrueV = Op.getOperand(1);
@@ -5624,6 +5683,15 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
if (SDValue V = combineSelectToBinOp(Op.getNode(), DAG, Subtarget))
return V;
+ if (Op.hasOneUse() && isBinOp(Op->use_begin()->getOpcode())) {
+ SDNode *BinOp = *Op->use_begin();
+ if (SDValue NewSel =
+ foldBinOpIntoSelectIfProfitable(*Op->use_begin(), DAG, Subtarget)) {
+ DAG.ReplaceAllUsesWith(BinOp, &NewSel);
+ return lowerSELECT(NewSel, DAG);
+ }
+ }
+
// (select cc, 1.0, 0.0) -> (sint_to_fp (zext cc))
// (select cc, 0.0, 1.0) -> (sint_to_fp (zext (xor cc, 1)))
const ConstantFPSDNode *FPTV = dyn_cast<ConstantFPSDNode>(TrueV);
diff --git a/llvm/test/CodeGen/RISCV/fold-binop-into-select.ll b/llvm/test/CodeGen/RISCV/fold-binop-into-select.ll
new file mode 100644
index 0000000000000..ba3b0201912d5
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/fold-binop-into-select.ll
@@ -0,0 +1,31 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc -mtriple=riscv64 < %s | FileCheck %s
+
+define i64 @select_add(i1 %c, i64 %x) {
+; CHECK-LABEL: select_add:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: andi a0, a0, 1
+; CHECK-NEXT: addi a1, a1, 2
+; CHECK-NEXT: addi a0, a0, -1
+; CHECK-NEXT: and a0, a0, a1
+; CHECK-NEXT: ret
+entry:
+ %select_ = select i1 %c, i64 -2, i64 %x
+ %res = add i64 %select_, 2
+ ret i64 %res
+}
+
+define i64 @select_and(i1 %c, i64 %x) {
+; CHECK-LABEL: select_and:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: andi a0, a0, 1
+; CHECK-NEXT: addiw a0, a0, -1
+; CHECK-NEXT: and a0, a1, a0
+; CHECK-NEXT: andi a0, a0, 64
+; CHECK-NEXT: ret
+entry:
+ %select_ = select i1 %c, i64 63, i64 %x
+ %res = and i64 %select_, 64
+ ret i64 %res
+}
+
More information about the llvm-commits
mailing list