diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index a157c94849f37..bb9951ea15355 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -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(TrueV) != isa(FalseV)) { + bool IsCZERO_NEZ = isa(TrueV); + SDValue ConstVal = IsCZERO_NEZ ? TrueV : FalseV; + SDValue RegV = IsCZERO_NEZ ? FalseV : TrueV; + int64_t RawConstVal = cast(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()) diff --git a/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll b/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll index b7b88584f3bdb..13c43a3875a08 100644 --- a/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll +++ b/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll @@ -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 @@ -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 diff --git a/llvm/test/CodeGen/RISCV/zicond-opts.ll b/llvm/test/CodeGen/RISCV/zicond-opts.ll index f5a25868bd12b..2512ba803cf48 100644 --- a/llvm/test/CodeGen/RISCV/zicond-opts.ll +++ b/llvm/test/CodeGen/RISCV/zicond-opts.ll @@ -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 @@ -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 @@ -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