[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