Skip to content

[RISCV] Lower SELECT's with one constant more efficiently using Zicond #143581

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

Merged
merged 1 commit into from
Jun 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9096,6 +9096,32 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
return DAG.getNode(ISD::ADD, DL, VT, CMOV, RHSVal);
}

// (select c, c1, t) -> (add (czero_nez t - c1, c), c1)
// (select c, t, c1) -> (add (czero_eqz t - c1, c), c1)
if (isa<ConstantSDNode>(TrueV) != isa<ConstantSDNode>(FalseV)) {
bool IsCZERO_NEZ = isa<ConstantSDNode>(TrueV);
SDValue ConstVal = IsCZERO_NEZ ? TrueV : FalseV;
SDValue RegV = IsCZERO_NEZ ? FalseV : TrueV;
int64_t RawConstVal = cast<ConstantSDNode>(ConstVal)->getSExtValue();
// Fall back to XORI if Const == -0x800
if (RawConstVal == -0x800) {
SDValue XorOp = DAG.getNode(ISD::XOR, DL, VT, RegV, ConstVal);
SDValue CMOV =
DAG.getNode(IsCZERO_NEZ ? RISCVISD::CZERO_NEZ : RISCVISD::CZERO_EQZ,
DL, VT, XorOp, CondV);
return DAG.getNode(ISD::XOR, DL, VT, CMOV, ConstVal);
}
// Efficient only if the constant and its negation fit into `ADDI`
// Prefer Add/Sub over Xor since can be compressed for small immediates
if (isInt<12>(RawConstVal)) {
SDValue SubOp = DAG.getNode(ISD::SUB, DL, VT, RegV, ConstVal);
SDValue CMOV =
DAG.getNode(IsCZERO_NEZ ? RISCVISD::CZERO_NEZ : RISCVISD::CZERO_EQZ,
DL, VT, SubOp, CondV);
return DAG.getNode(ISD::ADD, DL, VT, CMOV, ConstVal);
}
}

// (select c, t, f) -> (or (czero_eqz t, c), (czero_nez f, c))
// Unless we have the short forward branch optimization.
if (!Subtarget.hasConditionalMoveFusion())
Expand Down
46 changes: 30 additions & 16 deletions llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,21 @@ define signext i32 @test6(i32 signext %x, i32 signext %z) {
; NOSFB-NEXT: or a0, a0, a1
; NOSFB-NEXT: ret
;
; SFB-LABEL: test6:
; SFB: # %bb.0:
; SFB-NEXT: li a2, -1
; SFB-NEXT: beqz a1, .LBB5_2
; SFB-NEXT: # %bb.1:
; SFB-NEXT: mv a0, a2
; SFB-NEXT: .LBB5_2:
; SFB-NEXT: ret
; NOZICOND-LABEL: test6:
; NOZICOND: # %bb.0:
; NOZICOND-NEXT: li a2, -1
; NOZICOND-NEXT: beqz a1, .LBB5_2
; NOZICOND-NEXT: # %bb.1:
; NOZICOND-NEXT: mv a0, a2
; NOZICOND-NEXT: .LBB5_2:
; NOZICOND-NEXT: ret
;
; ZICOND-LABEL: test6:
; ZICOND: # %bb.0:
; ZICOND-NEXT: addi a0, a0, 1
; ZICOND-NEXT: czero.nez a0, a0, a1
; ZICOND-NEXT: addi a0, a0, -1
; ZICOND-NEXT: ret
%c = icmp eq i32 %z, 0
%b = select i1 %c, i32 %x, i32 -1
ret i32 %b
Expand All @@ -195,14 +202,21 @@ define signext i32 @test7(i32 signext %x, i32 signext %z) {
; NOSFB-NEXT: or a0, a0, a1
; NOSFB-NEXT: ret
;
; SFB-LABEL: test7:
; SFB: # %bb.0:
; SFB-NEXT: li a2, -1
; SFB-NEXT: bnez a1, .LBB6_2
; SFB-NEXT: # %bb.1:
; SFB-NEXT: mv a0, a2
; SFB-NEXT: .LBB6_2:
; SFB-NEXT: ret
; NOZICOND-LABEL: test7:
; NOZICOND: # %bb.0:
; NOZICOND-NEXT: li a2, -1
; NOZICOND-NEXT: bnez a1, .LBB6_2
; NOZICOND-NEXT: # %bb.1:
; NOZICOND-NEXT: mv a0, a2
; NOZICOND-NEXT: .LBB6_2:
; NOZICOND-NEXT: ret
;
; ZICOND-LABEL: test7:
; ZICOND: # %bb.0:
; ZICOND-NEXT: addi a0, a0, 1
; ZICOND-NEXT: czero.eqz a0, a0, a1
; ZICOND-NEXT: addi a0, a0, -1
; ZICOND-NEXT: ret
%c = icmp eq i32 %z, 0
%b = select i1 %c, i32 -1, i32 %x
ret i32 %b
Expand Down
38 changes: 16 additions & 22 deletions llvm/test/CodeGen/RISCV/zicond-opts.ll
Original file line number Diff line number Diff line change
Expand Up @@ -146,20 +146,18 @@ define i64 @select_imm_reg(i64 %t, i1 %cond) {
; RV32ZICOND-LABEL: select_imm_reg:
; RV32ZICOND: # %bb.0:
; RV32ZICOND-NEXT: andi a2, a2, 1
; RV32ZICOND-NEXT: li a3, 3
; RV32ZICOND-NEXT: czero.nez a0, a0, a2
; RV32ZICOND-NEXT: czero.eqz a3, a3, a2
; RV32ZICOND-NEXT: or a0, a3, a0
; RV32ZICOND-NEXT: addi a0, a0, -3
; RV32ZICOND-NEXT: czero.nez a1, a1, a2
; RV32ZICOND-NEXT: czero.nez a0, a0, a2
; RV32ZICOND-NEXT: addi a0, a0, 3
; RV32ZICOND-NEXT: ret
;
; RV64ZICOND-LABEL: select_imm_reg:
; RV64ZICOND: # %bb.0:
; RV64ZICOND-NEXT: andi a1, a1, 1
; RV64ZICOND-NEXT: li a2, 3
; RV64ZICOND-NEXT: addi a0, a0, -3
; RV64ZICOND-NEXT: czero.nez a0, a0, a1
; RV64ZICOND-NEXT: czero.eqz a1, a2, a1
; RV64ZICOND-NEXT: or a0, a1, a0
; RV64ZICOND-NEXT: addi a0, a0, 3
; RV64ZICOND-NEXT: ret
%4 = select i1 %cond, i64 3, i64 %t
ret i64 %4
Expand All @@ -170,20 +168,18 @@ define i64 @select_reg_imm(i64 %t, i1 %cond) {
; RV32ZICOND-LABEL: select_reg_imm:
; RV32ZICOND: # %bb.0:
; RV32ZICOND-NEXT: andi a2, a2, 1
; RV32ZICOND-NEXT: li a3, 3
; RV32ZICOND-NEXT: czero.nez a3, a3, a2
; RV32ZICOND-NEXT: czero.eqz a0, a0, a2
; RV32ZICOND-NEXT: or a0, a0, a3
; RV32ZICOND-NEXT: addi a0, a0, -3
; RV32ZICOND-NEXT: czero.eqz a1, a1, a2
; RV32ZICOND-NEXT: czero.eqz a0, a0, a2
; RV32ZICOND-NEXT: addi a0, a0, 3
; RV32ZICOND-NEXT: ret
;
; RV64ZICOND-LABEL: select_reg_imm:
; RV64ZICOND: # %bb.0:
; RV64ZICOND-NEXT: andi a1, a1, 1
; RV64ZICOND-NEXT: li a2, 3
; RV64ZICOND-NEXT: czero.nez a2, a2, a1
; RV64ZICOND-NEXT: addi a0, a0, -3
; RV64ZICOND-NEXT: czero.eqz a0, a0, a1
; RV64ZICOND-NEXT: or a0, a0, a2
; RV64ZICOND-NEXT: addi a0, a0, 3
; RV64ZICOND-NEXT: ret
%4 = select i1 %cond, i64 %t, i64 3
ret i64 %4
Expand All @@ -194,21 +190,19 @@ define i64 @select_imm_reg_neg_2048(i64 %t, i1 %cond) {
; RV32ZICOND-LABEL: select_imm_reg_neg_2048:
; RV32ZICOND: # %bb.0:
; RV32ZICOND-NEXT: andi a2, a2, 1
; RV32ZICOND-NEXT: li a3, -2048
; RV32ZICOND-NEXT: xori a0, a0, -2048
; RV32ZICOND-NEXT: neg a3, a2
; RV32ZICOND-NEXT: czero.nez a0, a0, a2
; RV32ZICOND-NEXT: czero.eqz a3, a3, a2
; RV32ZICOND-NEXT: neg a2, a2
; RV32ZICOND-NEXT: or a0, a3, a0
; RV32ZICOND-NEXT: or a1, a2, a1
; RV32ZICOND-NEXT: or a1, a3, a1
; RV32ZICOND-NEXT: xori a0, a0, -2048
; RV32ZICOND-NEXT: ret
;
; RV64ZICOND-LABEL: select_imm_reg_neg_2048:
; RV64ZICOND: # %bb.0:
; RV64ZICOND-NEXT: andi a1, a1, 1
; RV64ZICOND-NEXT: li a2, -2048
; RV64ZICOND-NEXT: xori a0, a0, -2048
; RV64ZICOND-NEXT: czero.nez a0, a0, a1
; RV64ZICOND-NEXT: czero.eqz a1, a2, a1
; RV64ZICOND-NEXT: or a0, a1, a0
; RV64ZICOND-NEXT: xori a0, a0, -2048
; RV64ZICOND-NEXT: ret
%4 = select i1 %cond, i64 -2048, i64 %t
ret i64 %4
Expand Down
Loading