[llvm] [RISCV] Lower SELECT's with one constant more efficiently using Zicond (PR #143581)
Ryan Buchner via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 10 12:14:25 PDT 2025
================
@@ -9073,19 +9078,36 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
}
}
- const int TrueValCost = RISCVMatInt::getIntMatCost(
- TrueVal, Subtarget.getXLen(), Subtarget, /*CompressionCost=*/true);
- const int FalseValCost = RISCVMatInt::getIntMatCost(
- FalseVal, Subtarget.getXLen(), Subtarget, /*CompressionCost=*/true);
- bool IsCZERO_NEZ = TrueValCost <= FalseValCost;
- SDValue LHSVal = DAG.getConstant(
- IsCZERO_NEZ ? FalseVal - TrueVal : TrueVal - FalseVal, DL, VT);
- SDValue RHSVal =
- DAG.getConstant(IsCZERO_NEZ ? TrueVal : FalseVal, DL, VT);
- SDValue CMOV =
- DAG.getNode(IsCZERO_NEZ ? RISCVISD::CZERO_NEZ : RISCVISD::CZERO_EQZ,
- DL, VT, LHSVal, CondV);
- return DAG.getNode(ISD::ADD, DL, VT, CMOV, RHSVal);
+ bool IsCZERO_NEZ;
+ SDValue ConstVal, SubOp;
+ if (BothAreConstant) {
+ const APInt &TrueVal = TrueV->getAsAPIntVal();
+ const APInt &FalseVal = FalseV->getAsAPIntVal();
+ const int TrueValCost = RISCVMatInt::getIntMatCost(
+ TrueVal, Subtarget.getXLen(), Subtarget, /*CompressionCost=*/true);
+ const int FalseValCost = RISCVMatInt::getIntMatCost(
+ FalseVal, Subtarget.getXLen(), Subtarget, /*CompressionCost=*/true);
+ IsCZERO_NEZ = TrueValCost <= FalseValCost;
+
+ SubOp = DAG.getConstant(
+ IsCZERO_NEZ ? FalseVal - TrueVal : TrueVal - FalseVal, DL, VT);
+ ConstVal = DAG.getConstant(IsCZERO_NEZ ? TrueVal : FalseVal, DL, VT);
+ } else {
+ IsCZERO_NEZ = isa<ConstantSDNode>(TrueV);
+ ConstVal = IsCZERO_NEZ ? TrueV : FalseV;
+
+ SDValue &RegV = IsCZERO_NEZ ? FalseV : TrueV;
+ SubOp = DAG.getNode(ISD::SUB, DL, VT, RegV, ConstVal);
+ }
+ // The one constant case is only efficient is the constant fits into
+ // `ADDI`
+ if (BothAreConstant ||
----------------
bababuck wrote:
This only applies for the one constant case (i.e. `select cond, const, reg`), but if the value doesn't fit into an `addi` instruction there will be no improvement from an instruction count perspective with this new transformation. >From a micro-architectural perspective, this transformation with be worse in the large immediate case because all of the instructions are dependent on each other, which previously the first two instruction were independent and could issue in parallel on an architecture that supports multi-issue.
The two constant case is different since we can perform the initial subtraction at compile time which eliminates one instruction.
Before the change for large immediate:
```
%1 = li %imm
%2 = czero.eqz %reg, %cond
%3 = czero.nez %1, %cond
%4 = or %2, %3
ret %4
```
After the change for large immediate.
```
%1 = li %imm
%2 = sub %reg, %1
%3 = czero.eqz %2, %cond
%4 = add %3, %1
ret %4
```
https://github.com/llvm/llvm-project/pull/143581
More information about the llvm-commits
mailing list