diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -8991,6 +8991,24 @@ {LHS, RHS, TargetCC, TrueV, FalseV}); } + // Optimize + // (select_cc (and X, 0x80000000), 0, seteq, trueV, falseV) -> + // (select_cc (sext_inreg X, i32), 0, setge, trueV, falseV) + // And + // (select_cc (and X, 0x80000000), 0, setne, trueV, falseV) -> + // (select_cc (sext_inreg X, i32), 0, setlt, trueV, falseV) + if (Subtarget.is64Bit() && LHS.getValueType() == MVT::i64 && + isNullConstant(RHS) && LHS.getOpcode() == ISD::AND && LHS.hasOneUse() && + isa(LHS.getOperand(1)) && + LHS.getConstantOperandVal(1) == UINT64_C(0x80000000)) { + SDLoc DL(N); + CCVal = CCVal == ISD::SETEQ ? ISD::SETGE : ISD::SETLT; + SDValue TargetCC = DAG.getCondCode(CCVal); + LHS = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, + LHS.getOperand(0), DAG.getValueType(MVT::i32)); + return DAG.getNode(RISCVISD::SELECT_CC, DL, N->getValueType(0), + {LHS, RHS, TargetCC, TrueV, FalseV}); + } break; } case RISCVISD::BR_CC: { @@ -9042,6 +9060,26 @@ N->getOperand(0), LHS, RHS, TargetCC, N->getOperand(4)); } + + // Optimize + // (br_cc (and X, 0x80000000), 0, seteq, dest) -> + // (br_cc (sext_inreg X, i32), 0, setge, dest) + // And + // (br_cc (and X, 0x80000000), 0, setne, dest) -> + // (br_cc (sext_inreg X, i32), 0, setlt, dest) + if (Subtarget.is64Bit() && LHS.getValueType() == MVT::i64 && + isNullConstant(RHS) && LHS.getOpcode() == ISD::AND && LHS.hasOneUse() && + isa(LHS.getOperand(1)) && + LHS.getConstantOperandVal(1) == UINT64_C(0x80000000)) { + SDLoc DL(N); + CCVal = CCVal == ISD::SETEQ ? ISD::SETGE : ISD::SETLT; + SDValue TargetCC = DAG.getCondCode(CCVal); + LHS = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, + LHS.getOperand(0), DAG.getValueType(MVT::i32)); + return DAG.getNode(RISCVISD::BR_CC, DL, N->getValueType(0), + N->getOperand(0), LHS, RHS, TargetCC, + N->getOperand(4)); + } break; } case ISD::BITREVERSE: diff --git a/llvm/test/CodeGen/RISCV/i64-icmp.ll b/llvm/test/CodeGen/RISCV/i64-icmp.ll --- a/llvm/test/CodeGen/RISCV/i64-icmp.ll +++ b/llvm/test/CodeGen/RISCV/i64-icmp.ll @@ -738,3 +738,79 @@ %3 = zext i1 %2 to i64 ret i64 %3 } + +define i64 @icmp_bit31_eq_zero_select(i64 %a, i64 %b, i64 %c) nounwind { +; RV64I-LABEL: icmp_bit31_eq_zero_select: +; RV64I: # %bb.0: +; RV64I-NEXT: sext.w a3, a0 +; RV64I-NEXT: mv a0, a1 +; RV64I-NEXT: bgez a3, .LBB66_2 +; RV64I-NEXT: # %bb.1: +; RV64I-NEXT: mv a0, a2 +; RV64I-NEXT: .LBB66_2: +; RV64I-NEXT: ret + %1 = and i64 %a, 2147483648 + %2 = icmp eq i64 %1, 0 + %3 = select i1 %2, i64 %b, i64 %c + ret i64 %3 +} + +define i64 @icmp_bit31_ne_zero_select(i64 %a, i64 %b, i64 %c) nounwind { +; RV64I-LABEL: icmp_bit31_ne_zero_select: +; RV64I: # %bb.0: +; RV64I-NEXT: srliw a3, a0, 31 +; RV64I-NEXT: mv a0, a1 +; RV64I-NEXT: bnez a3, .LBB67_2 +; RV64I-NEXT: # %bb.1: +; RV64I-NEXT: mv a0, a2 +; RV64I-NEXT: .LBB67_2: +; RV64I-NEXT: ret + %1 = and i64 %a, 2147483648 + %2 = icmp ne i64 %1, 0 + %3 = select i1 %2, i64 %b, i64 %c + ret i64 %3 +} + +declare void @bar() + +define void @icmp_bit31_eq_zero_branch(i64 %0) { +; RV64I-LABEL: icmp_bit31_eq_zero_branch: +; RV64I: # %bb.0: +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: bltz a0, .LBB68_2 +; RV64I-NEXT: # %bb.1: +; RV64I-NEXT: tail bar@plt +; RV64I-NEXT: .LBB68_2: +; RV64I-NEXT: ret + %2 = and i64 %0, 2147483648 + %3 = icmp eq i64 %2, 0 + br i1 %3, label %4, label %5 + +4: + tail call void @bar() + br label %5 + +5: + ret void +} + +define void @icmp_bit31_ne_zero_branch(i64 %0) { +; RV64I-LABEL: icmp_bit31_ne_zero_branch: +; RV64I: # %bb.0: +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: bgez a0, .LBB69_2 +; RV64I-NEXT: # %bb.1: +; RV64I-NEXT: tail bar@plt +; RV64I-NEXT: .LBB69_2: +; RV64I-NEXT: ret + %2 = and i64 %0, 2147483648 + %3 = icmp ne i64 %2, 0 + br i1 %3, label %4, label %5 + +4: + tail call void @bar() + br label %5 + +5: + ret void +}