[llvm] [RISCV] Prefer (select (x < 0), y, z) -> x >> (XLEN - 1) & (y - z) + z even with Zicond. (PR #125772)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 4 14:18:09 PST 2025
https://github.com/topperc created https://github.com/llvm/llvm-project/pull/125772
The Zicond version of this requires an li instruction and an
additional register.
Without Zicond we match this in a DAGCombine on RISCVISD::SELECT_CC.
>From 010c851013b44421e2f94a86b8b348d67ce59545 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Tue, 4 Feb 2025 13:31:27 -0800
Subject: [PATCH 1/2] [RISCV] Add Zicond run lines to select-const.ll. NFC
---
llvm/test/CodeGen/RISCV/select-const.ll | 198 +++++++++++++++++++-----
1 file changed, 156 insertions(+), 42 deletions(-)
diff --git a/llvm/test/CodeGen/RISCV/select-const.ll b/llvm/test/CodeGen/RISCV/select-const.ll
index 6a24d03de87497..9201338cc78691 100644
--- a/llvm/test/CodeGen/RISCV/select-const.ll
+++ b/llvm/test/CodeGen/RISCV/select-const.ll
@@ -3,10 +3,14 @@
; RUN: | FileCheck -check-prefixes=RV32,RV32I %s
; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi=ilp32 -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefixes=RV32,RV32IF %s
+; RUN: llc -mtriple=riscv32 -mattr=+zicond -target-abi=ilp32 -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefixes=RV32,RV32ZICOND %s
; RUN: llc -mtriple=riscv64 -target-abi=lp64 -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefixes=RV64,RV64I %s
; RUN: llc -mtriple=riscv64 -mattr=+f,+d -target-abi=lp64 -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefixes=RV64,RV64IFD %s
+; RUN: llc -mtriple=riscv64 -mattr=+zicond -target-abi=lp64 -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefixes=RV64,RV64ZICOND %s
;; This tests how good we are at materialising constants using `select`. The aim
;; is that we do so without a branch if possible (at the moment our lowering of
@@ -59,25 +63,59 @@ define signext i32 @select_const_int_pow2_zero(i1 zeroext %a) nounwind {
}
define signext i32 @select_const_int_harder(i1 zeroext %a) nounwind {
-; RV32-LABEL: select_const_int_harder:
-; RV32: # %bb.0:
-; RV32-NEXT: bnez a0, .LBB3_2
-; RV32-NEXT: # %bb.1:
-; RV32-NEXT: li a0, 38
-; RV32-NEXT: ret
-; RV32-NEXT: .LBB3_2:
-; RV32-NEXT: li a0, 6
-; RV32-NEXT: ret
+; RV32I-LABEL: select_const_int_harder:
+; RV32I: # %bb.0:
+; RV32I-NEXT: bnez a0, .LBB3_2
+; RV32I-NEXT: # %bb.1:
+; RV32I-NEXT: li a0, 38
+; RV32I-NEXT: ret
+; RV32I-NEXT: .LBB3_2:
+; RV32I-NEXT: li a0, 6
+; RV32I-NEXT: ret
;
-; RV64-LABEL: select_const_int_harder:
-; RV64: # %bb.0:
-; RV64-NEXT: bnez a0, .LBB3_2
-; RV64-NEXT: # %bb.1:
-; RV64-NEXT: li a0, 38
-; RV64-NEXT: ret
-; RV64-NEXT: .LBB3_2:
-; RV64-NEXT: li a0, 6
-; RV64-NEXT: ret
+; RV32IF-LABEL: select_const_int_harder:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: bnez a0, .LBB3_2
+; RV32IF-NEXT: # %bb.1:
+; RV32IF-NEXT: li a0, 38
+; RV32IF-NEXT: ret
+; RV32IF-NEXT: .LBB3_2:
+; RV32IF-NEXT: li a0, 6
+; RV32IF-NEXT: ret
+;
+; RV32ZICOND-LABEL: select_const_int_harder:
+; RV32ZICOND: # %bb.0:
+; RV32ZICOND-NEXT: li a1, 32
+; RV32ZICOND-NEXT: czero.nez a0, a1, a0
+; RV32ZICOND-NEXT: addi a0, a0, 6
+; RV32ZICOND-NEXT: ret
+;
+; RV64I-LABEL: select_const_int_harder:
+; RV64I: # %bb.0:
+; RV64I-NEXT: bnez a0, .LBB3_2
+; RV64I-NEXT: # %bb.1:
+; RV64I-NEXT: li a0, 38
+; RV64I-NEXT: ret
+; RV64I-NEXT: .LBB3_2:
+; RV64I-NEXT: li a0, 6
+; RV64I-NEXT: ret
+;
+; RV64IFD-LABEL: select_const_int_harder:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: bnez a0, .LBB3_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: li a0, 38
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB3_2:
+; RV64IFD-NEXT: li a0, 6
+; RV64IFD-NEXT: ret
+;
+; RV64ZICOND-LABEL: select_const_int_harder:
+; RV64ZICOND: # %bb.0:
+; RV64ZICOND-NEXT: li a1, 32
+; RV64ZICOND-NEXT: czero.nez a0, a1, a0
+; RV64ZICOND-NEXT: addi a0, a0, 6
+; RV64ZICOND-NEXT: ret
%1 = select i1 %a, i32 6, i32 38
ret i32 %1
}
@@ -106,6 +144,14 @@ define float @select_const_fp(i1 zeroext %a) nounwind {
; RV32IF-NEXT: fmv.x.w a0, fa5
; RV32IF-NEXT: ret
;
+; RV32ZICOND-LABEL: select_const_fp:
+; RV32ZICOND: # %bb.0:
+; RV32ZICOND-NEXT: lui a1, 1024
+; RV32ZICOND-NEXT: czero.nez a0, a1, a0
+; RV32ZICOND-NEXT: lui a1, 263168
+; RV32ZICOND-NEXT: add a0, a0, a1
+; RV32ZICOND-NEXT: ret
+;
; RV64I-LABEL: select_const_fp:
; RV64I: # %bb.0:
; RV64I-NEXT: mv a1, a0
@@ -128,6 +174,14 @@ define float @select_const_fp(i1 zeroext %a) nounwind {
; RV64IFD-NEXT: fmv.w.x fa5, a0
; RV64IFD-NEXT: fmv.x.w a0, fa5
; RV64IFD-NEXT: ret
+;
+; RV64ZICOND-LABEL: select_const_fp:
+; RV64ZICOND: # %bb.0:
+; RV64ZICOND-NEXT: lui a1, 1024
+; RV64ZICOND-NEXT: czero.nez a0, a1, a0
+; RV64ZICOND-NEXT: lui a1, 263168
+; RV64ZICOND-NEXT: add a0, a0, a1
+; RV64ZICOND-NEXT: ret
%1 = select i1 %a, float 3.0, float 4.0
ret float %1
}
@@ -391,38 +445,98 @@ define i32 @select_ne_10001_10002(i32 signext %a, i32 signext %b) {
}
define i32 @select_slt_zero_constant1_constant2(i32 signext %x) {
-; RV32-LABEL: select_slt_zero_constant1_constant2:
-; RV32: # %bb.0:
-; RV32-NEXT: srai a0, a0, 31
-; RV32-NEXT: andi a0, a0, 10
-; RV32-NEXT: addi a0, a0, -3
-; RV32-NEXT: ret
+; RV32I-LABEL: select_slt_zero_constant1_constant2:
+; RV32I: # %bb.0:
+; RV32I-NEXT: srai a0, a0, 31
+; RV32I-NEXT: andi a0, a0, 10
+; RV32I-NEXT: addi a0, a0, -3
+; RV32I-NEXT: ret
;
-; RV64-LABEL: select_slt_zero_constant1_constant2:
-; RV64: # %bb.0:
-; RV64-NEXT: srai a0, a0, 63
-; RV64-NEXT: andi a0, a0, 10
-; RV64-NEXT: addi a0, a0, -3
-; RV64-NEXT: ret
+; RV32IF-LABEL: select_slt_zero_constant1_constant2:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: srai a0, a0, 31
+; RV32IF-NEXT: andi a0, a0, 10
+; RV32IF-NEXT: addi a0, a0, -3
+; RV32IF-NEXT: ret
+;
+; RV32ZICOND-LABEL: select_slt_zero_constant1_constant2:
+; RV32ZICOND: # %bb.0:
+; RV32ZICOND-NEXT: slti a0, a0, 0
+; RV32ZICOND-NEXT: li a1, -10
+; RV32ZICOND-NEXT: czero.nez a0, a1, a0
+; RV32ZICOND-NEXT: addi a0, a0, 7
+; RV32ZICOND-NEXT: ret
+;
+; RV64I-LABEL: select_slt_zero_constant1_constant2:
+; RV64I: # %bb.0:
+; RV64I-NEXT: srai a0, a0, 63
+; RV64I-NEXT: andi a0, a0, 10
+; RV64I-NEXT: addi a0, a0, -3
+; RV64I-NEXT: ret
+;
+; RV64IFD-LABEL: select_slt_zero_constant1_constant2:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: srai a0, a0, 63
+; RV64IFD-NEXT: andi a0, a0, 10
+; RV64IFD-NEXT: addi a0, a0, -3
+; RV64IFD-NEXT: ret
+;
+; RV64ZICOND-LABEL: select_slt_zero_constant1_constant2:
+; RV64ZICOND: # %bb.0:
+; RV64ZICOND-NEXT: slti a0, a0, 0
+; RV64ZICOND-NEXT: li a1, -10
+; RV64ZICOND-NEXT: czero.nez a0, a1, a0
+; RV64ZICOND-NEXT: addi a0, a0, 7
+; RV64ZICOND-NEXT: ret
%cmp = icmp slt i32 %x, 0
%cond = select i1 %cmp, i32 7, i32 -3
ret i32 %cond
}
define i32 @select_sgt_negative_one_constant1_constant2(i32 signext %x) {
-; RV32-LABEL: select_sgt_negative_one_constant1_constant2:
-; RV32: # %bb.0:
-; RV32-NEXT: srai a0, a0, 31
-; RV32-NEXT: andi a0, a0, -10
-; RV32-NEXT: addi a0, a0, 7
-; RV32-NEXT: ret
+; RV32I-LABEL: select_sgt_negative_one_constant1_constant2:
+; RV32I: # %bb.0:
+; RV32I-NEXT: srai a0, a0, 31
+; RV32I-NEXT: andi a0, a0, -10
+; RV32I-NEXT: addi a0, a0, 7
+; RV32I-NEXT: ret
;
-; RV64-LABEL: select_sgt_negative_one_constant1_constant2:
-; RV64: # %bb.0:
-; RV64-NEXT: srai a0, a0, 63
-; RV64-NEXT: andi a0, a0, -10
-; RV64-NEXT: addi a0, a0, 7
-; RV64-NEXT: ret
+; RV32IF-LABEL: select_sgt_negative_one_constant1_constant2:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: srai a0, a0, 31
+; RV32IF-NEXT: andi a0, a0, -10
+; RV32IF-NEXT: addi a0, a0, 7
+; RV32IF-NEXT: ret
+;
+; RV32ZICOND-LABEL: select_sgt_negative_one_constant1_constant2:
+; RV32ZICOND: # %bb.0:
+; RV32ZICOND-NEXT: slti a0, a0, 0
+; RV32ZICOND-NEXT: li a1, -10
+; RV32ZICOND-NEXT: czero.eqz a0, a1, a0
+; RV32ZICOND-NEXT: addi a0, a0, 7
+; RV32ZICOND-NEXT: ret
+;
+; RV64I-LABEL: select_sgt_negative_one_constant1_constant2:
+; RV64I: # %bb.0:
+; RV64I-NEXT: srai a0, a0, 63
+; RV64I-NEXT: andi a0, a0, -10
+; RV64I-NEXT: addi a0, a0, 7
+; RV64I-NEXT: ret
+;
+; RV64IFD-LABEL: select_sgt_negative_one_constant1_constant2:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: srai a0, a0, 63
+; RV64IFD-NEXT: andi a0, a0, -10
+; RV64IFD-NEXT: addi a0, a0, 7
+; RV64IFD-NEXT: ret
+;
+; RV64ZICOND-LABEL: select_sgt_negative_one_constant1_constant2:
+; RV64ZICOND: # %bb.0:
+; RV64ZICOND-NEXT: slti a0, a0, 0
+; RV64ZICOND-NEXT: li a1, -10
+; RV64ZICOND-NEXT: czero.eqz a0, a1, a0
+; RV64ZICOND-NEXT: addi a0, a0, 7
+; RV64ZICOND-NEXT: ret
%cmp = icmp sgt i32 %x, -1
%cond = select i1 %cmp, i32 7, i32 -3
ret i32 %cond
>From 962c545ed387f80b9cebae8b7f71cc4e7e54ba27 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Tue, 4 Feb 2025 13:38:46 -0800
Subject: [PATCH 2/2] [RISCV] Prefer (select (x < 0), y, z) -> x >> (XLEN - 1)
& (y - z) + z even with Zicond.
The Zicond version of this requires an li instruction and an
additional register.
Without Zicond we match this in a DAGCombine on RISCVISD::SELECT_CC.
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 27 +++++
llvm/test/CodeGen/RISCV/select-const.ll | 108 +++++---------------
2 files changed, 51 insertions(+), 84 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 2d2213b420f5a4..1120524d77902d 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -8378,6 +8378,33 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV)) {
const APInt &TrueVal = TrueV->getAsAPIntVal();
const APInt &FalseVal = FalseV->getAsAPIntVal();
+
+ // Prefer these over Zicond to avoid materializing an immediate:
+ // (select (x < 0), y, z) -> x >> (XLEN - 1) & (y - z) + z
+ // (select (x > -1), z, y) -> x >> (XLEN - 1) & (y - z) + z
+ if (CondV.getOpcode() == ISD::SETCC &&
+ CondV.getOperand(0).getValueType() == VT && CondV.hasOneUse()) {
+ ISD::CondCode CCVal = cast<CondCodeSDNode>(CondV.getOperand(2))->get();
+ if ((CCVal == ISD::SETLT && isNullConstant(CondV.getOperand(1))) ||
+ (CCVal == ISD::SETGT && isAllOnesConstant(CondV.getOperand(1)))) {
+ int64_t TrueImm = TrueVal.getSExtValue();
+ int64_t FalseImm = FalseVal.getSExtValue();
+ if (CCVal == ISD::SETGT)
+ std::swap(TrueImm, FalseImm);
+ if (isInt<12>(TrueImm) && isInt<12>(FalseImm) &&
+ isInt<12>(TrueImm - FalseImm)) {
+ SDValue SRA =
+ DAG.getNode(ISD::SRA, DL, VT, CondV.getOperand(0),
+ DAG.getConstant(Subtarget.getXLen() - 1, DL, VT));
+ SDValue AND =
+ DAG.getNode(ISD::AND, DL, VT, SRA,
+ DAG.getSignedConstant(TrueImm - FalseImm, DL, VT));
+ return DAG.getNode(ISD::ADD, DL, VT, AND,
+ DAG.getSignedConstant(FalseImm, DL, VT));
+ }
+ }
+ }
+
const int TrueValCost = RISCVMatInt::getIntMatCost(
TrueVal, Subtarget.getXLen(), Subtarget, /*CompressionCost=*/true);
const int FalseValCost = RISCVMatInt::getIntMatCost(
diff --git a/llvm/test/CodeGen/RISCV/select-const.ll b/llvm/test/CodeGen/RISCV/select-const.ll
index 9201338cc78691..90a81c535cef29 100644
--- a/llvm/test/CodeGen/RISCV/select-const.ll
+++ b/llvm/test/CodeGen/RISCV/select-const.ll
@@ -445,98 +445,38 @@ define i32 @select_ne_10001_10002(i32 signext %a, i32 signext %b) {
}
define i32 @select_slt_zero_constant1_constant2(i32 signext %x) {
-; RV32I-LABEL: select_slt_zero_constant1_constant2:
-; RV32I: # %bb.0:
-; RV32I-NEXT: srai a0, a0, 31
-; RV32I-NEXT: andi a0, a0, 10
-; RV32I-NEXT: addi a0, a0, -3
-; RV32I-NEXT: ret
-;
-; RV32IF-LABEL: select_slt_zero_constant1_constant2:
-; RV32IF: # %bb.0:
-; RV32IF-NEXT: srai a0, a0, 31
-; RV32IF-NEXT: andi a0, a0, 10
-; RV32IF-NEXT: addi a0, a0, -3
-; RV32IF-NEXT: ret
-;
-; RV32ZICOND-LABEL: select_slt_zero_constant1_constant2:
-; RV32ZICOND: # %bb.0:
-; RV32ZICOND-NEXT: slti a0, a0, 0
-; RV32ZICOND-NEXT: li a1, -10
-; RV32ZICOND-NEXT: czero.nez a0, a1, a0
-; RV32ZICOND-NEXT: addi a0, a0, 7
-; RV32ZICOND-NEXT: ret
-;
-; RV64I-LABEL: select_slt_zero_constant1_constant2:
-; RV64I: # %bb.0:
-; RV64I-NEXT: srai a0, a0, 63
-; RV64I-NEXT: andi a0, a0, 10
-; RV64I-NEXT: addi a0, a0, -3
-; RV64I-NEXT: ret
-;
-; RV64IFD-LABEL: select_slt_zero_constant1_constant2:
-; RV64IFD: # %bb.0:
-; RV64IFD-NEXT: srai a0, a0, 63
-; RV64IFD-NEXT: andi a0, a0, 10
-; RV64IFD-NEXT: addi a0, a0, -3
-; RV64IFD-NEXT: ret
+; RV32-LABEL: select_slt_zero_constant1_constant2:
+; RV32: # %bb.0:
+; RV32-NEXT: srai a0, a0, 31
+; RV32-NEXT: andi a0, a0, 10
+; RV32-NEXT: addi a0, a0, -3
+; RV32-NEXT: ret
;
-; RV64ZICOND-LABEL: select_slt_zero_constant1_constant2:
-; RV64ZICOND: # %bb.0:
-; RV64ZICOND-NEXT: slti a0, a0, 0
-; RV64ZICOND-NEXT: li a1, -10
-; RV64ZICOND-NEXT: czero.nez a0, a1, a0
-; RV64ZICOND-NEXT: addi a0, a0, 7
-; RV64ZICOND-NEXT: ret
+; RV64-LABEL: select_slt_zero_constant1_constant2:
+; RV64: # %bb.0:
+; RV64-NEXT: srai a0, a0, 63
+; RV64-NEXT: andi a0, a0, 10
+; RV64-NEXT: addi a0, a0, -3
+; RV64-NEXT: ret
%cmp = icmp slt i32 %x, 0
%cond = select i1 %cmp, i32 7, i32 -3
ret i32 %cond
}
define i32 @select_sgt_negative_one_constant1_constant2(i32 signext %x) {
-; RV32I-LABEL: select_sgt_negative_one_constant1_constant2:
-; RV32I: # %bb.0:
-; RV32I-NEXT: srai a0, a0, 31
-; RV32I-NEXT: andi a0, a0, -10
-; RV32I-NEXT: addi a0, a0, 7
-; RV32I-NEXT: ret
-;
-; RV32IF-LABEL: select_sgt_negative_one_constant1_constant2:
-; RV32IF: # %bb.0:
-; RV32IF-NEXT: srai a0, a0, 31
-; RV32IF-NEXT: andi a0, a0, -10
-; RV32IF-NEXT: addi a0, a0, 7
-; RV32IF-NEXT: ret
-;
-; RV32ZICOND-LABEL: select_sgt_negative_one_constant1_constant2:
-; RV32ZICOND: # %bb.0:
-; RV32ZICOND-NEXT: slti a0, a0, 0
-; RV32ZICOND-NEXT: li a1, -10
-; RV32ZICOND-NEXT: czero.eqz a0, a1, a0
-; RV32ZICOND-NEXT: addi a0, a0, 7
-; RV32ZICOND-NEXT: ret
-;
-; RV64I-LABEL: select_sgt_negative_one_constant1_constant2:
-; RV64I: # %bb.0:
-; RV64I-NEXT: srai a0, a0, 63
-; RV64I-NEXT: andi a0, a0, -10
-; RV64I-NEXT: addi a0, a0, 7
-; RV64I-NEXT: ret
-;
-; RV64IFD-LABEL: select_sgt_negative_one_constant1_constant2:
-; RV64IFD: # %bb.0:
-; RV64IFD-NEXT: srai a0, a0, 63
-; RV64IFD-NEXT: andi a0, a0, -10
-; RV64IFD-NEXT: addi a0, a0, 7
-; RV64IFD-NEXT: ret
+; RV32-LABEL: select_sgt_negative_one_constant1_constant2:
+; RV32: # %bb.0:
+; RV32-NEXT: srai a0, a0, 31
+; RV32-NEXT: andi a0, a0, -10
+; RV32-NEXT: addi a0, a0, 7
+; RV32-NEXT: ret
;
-; RV64ZICOND-LABEL: select_sgt_negative_one_constant1_constant2:
-; RV64ZICOND: # %bb.0:
-; RV64ZICOND-NEXT: slti a0, a0, 0
-; RV64ZICOND-NEXT: li a1, -10
-; RV64ZICOND-NEXT: czero.eqz a0, a1, a0
-; RV64ZICOND-NEXT: addi a0, a0, 7
-; RV64ZICOND-NEXT: ret
+; RV64-LABEL: select_sgt_negative_one_constant1_constant2:
+; RV64: # %bb.0:
+; RV64-NEXT: srai a0, a0, 63
+; RV64-NEXT: andi a0, a0, -10
+; RV64-NEXT: addi a0, a0, 7
+; RV64-NEXT: ret
%cmp = icmp sgt i32 %x, -1
%cond = select i1 %cmp, i32 7, i32 -3
ret i32 %cond
More information about the llvm-commits
mailing list