diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index ce03818b49502..8763f0091b8c2 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -16639,33 +16639,38 @@ static SDValue performSETCCCombine(SDNode *N, SelectionDAG &DAG, } static SDValue -performSIGN_EXTEND_INREGCombine(SDNode *N, SelectionDAG &DAG, +performSIGN_EXTEND_INREGCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const RISCVSubtarget &Subtarget) { + SelectionDAG &DAG = DCI.DAG; SDValue Src = N->getOperand(0); EVT VT = N->getValueType(0); EVT SrcVT = cast(N->getOperand(1))->getVT(); unsigned Opc = Src.getOpcode(); + SDLoc DL(N); // Fold (sext_inreg (fmv_x_anyexth X), i16) -> (fmv_x_signexth X) // Don't do this with Zhinx. We need to explicitly sign extend the GPR. if (Opc == RISCVISD::FMV_X_ANYEXTH && SrcVT.bitsGE(MVT::i16) && Subtarget.hasStdExtZfhmin()) - return DAG.getNode(RISCVISD::FMV_X_SIGNEXTH, SDLoc(N), VT, - Src.getOperand(0)); + return DAG.getNode(RISCVISD::FMV_X_SIGNEXTH, DL, VT, Src.getOperand(0)); // Fold (sext_inreg (shl X, Y), i32) -> (sllw X, Y) iff Y u< 32 if (Opc == ISD::SHL && Subtarget.is64Bit() && SrcVT == MVT::i32 && VT == MVT::i64 && !isa(Src.getOperand(1)) && DAG.computeKnownBits(Src.getOperand(1)).countMaxActiveBits() <= 5) - return DAG.getNode(RISCVISD::SLLW, SDLoc(N), VT, Src.getOperand(0), + return DAG.getNode(RISCVISD::SLLW, DL, VT, Src.getOperand(0), Src.getOperand(1)); + // Fold (sext_inreg (setcc), i1) -> (sub 0, (setcc)) + if (Opc == ISD::SETCC && SrcVT == MVT::i1 && DCI.isAfterLegalizeDAG()) + return DAG.getNode(ISD::SUB, DL, VT, DAG.getConstant(0, DL, VT), Src); + // Fold (sext_inreg (xor (setcc), -1), i1) -> (add (setcc), -1) if (Opc == ISD::XOR && SrcVT == MVT::i1 && isAllOnesConstant(Src.getOperand(1)) && - Src.getOperand(0).getOpcode() == ISD::SETCC) - return DAG.getNode(ISD::ADD, SDLoc(N), VT, Src.getOperand(0), - DAG.getAllOnesConstant(SDLoc(N), VT)); + Src.getOperand(0).getOpcode() == ISD::SETCC && DCI.isAfterLegalizeDAG()) + return DAG.getNode(ISD::ADD, DL, VT, Src.getOperand(0), + DAG.getAllOnesConstant(DL, VT)); return SDValue(); } @@ -20088,7 +20093,7 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N, case ISD::SETCC: return performSETCCCombine(N, DAG, Subtarget); case ISD::SIGN_EXTEND_INREG: - return performSIGN_EXTEND_INREGCombine(N, DAG, Subtarget); + return performSIGN_EXTEND_INREGCombine(N, DCI, Subtarget); case ISD::ZERO_EXTEND: // Fold (zero_extend (fp_to_uint X)) to prevent forming fcvt+zexti32 during // type legalization. This is safe because fp_to_uint produces poison if diff --git a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll index 85666f70ce535..4a0cddb618a09 100644 --- a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll +++ b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll @@ -346,6 +346,31 @@ define zeroext i8 @sexti1_i32_setcc(i32 signext %a) { ret i8 %sext } +; Make sure we don't use seqz+nds.bfos instead of snez+addi +define i32 @sexti1_i32_setcc_2(i32 %a, i32 %b) { +; CHECK-LABEL: sexti1_i32_setcc_2: +; CHECK: # %bb.0: +; CHECK-NEXT: xor a0, a0, a1 +; CHECK-NEXT: snez a0, a0 +; CHECK-NEXT: addi a0, a0, -1 +; CHECK-NEXT: ret + %icmp = icmp eq i32 %a, %b + %sext = sext i1 %icmp to i32 + ret i32 %sext +} + +; Make sure we don't use nds.bfos instead of neg. +define i32 @sexti1_i32_setcc_3(i32 %a, i32 %b) { +; CHECK-LABEL: sexti1_i32_setcc_3: +; CHECK: # %bb.0: +; CHECK-NEXT: slt a0, a0, a1 +; CHECK-NEXT: neg a0, a0 +; CHECK-NEXT: ret + %icmp = icmp slt i32 %a, %b + %sext = sext i1 %icmp to i32 + ret i32 %sext +} + define i32 @sexti8_i32(i32 %a) { ; CHECK-LABEL: sexti8_i32: ; CHECK: # %bb.0: diff --git a/llvm/test/CodeGen/RISCV/rv32xtheadbb.ll b/llvm/test/CodeGen/RISCV/rv32xtheadbb.ll index ec720e6d8f5b0..d561145711fd9 100644 --- a/llvm/test/CodeGen/RISCV/rv32xtheadbb.ll +++ b/llvm/test/CodeGen/RISCV/rv32xtheadbb.ll @@ -372,6 +372,44 @@ define zeroext i8 @sexti1_i32_setcc(i32 signext %a) { ret i8 %sext } +; Make sure we don't use seqz+th.ext instead of snez+addi +define i32 @sexti1_i32_setcc_2(i32 %a, i32 %b) { +; RV32I-LABEL: sexti1_i32_setcc_2: +; RV32I: # %bb.0: +; RV32I-NEXT: xor a0, a0, a1 +; RV32I-NEXT: snez a0, a0 +; RV32I-NEXT: addi a0, a0, -1 +; RV32I-NEXT: ret +; +; RV32XTHEADBB-LABEL: sexti1_i32_setcc_2: +; RV32XTHEADBB: # %bb.0: +; RV32XTHEADBB-NEXT: xor a0, a0, a1 +; RV32XTHEADBB-NEXT: snez a0, a0 +; RV32XTHEADBB-NEXT: addi a0, a0, -1 +; RV32XTHEADBB-NEXT: ret + %icmp = icmp eq i32 %a, %b + %sext = sext i1 %icmp to i32 + ret i32 %sext +} + +; Make sure we don't use th.ext instead of neg. +define i32 @sexti1_i32_setcc_3(i32 %a, i32 %b) { +; RV32I-LABEL: sexti1_i32_setcc_3: +; RV32I: # %bb.0: +; RV32I-NEXT: slt a0, a0, a1 +; RV32I-NEXT: neg a0, a0 +; RV32I-NEXT: ret +; +; RV32XTHEADBB-LABEL: sexti1_i32_setcc_3: +; RV32XTHEADBB: # %bb.0: +; RV32XTHEADBB-NEXT: slt a0, a0, a1 +; RV32XTHEADBB-NEXT: neg a0, a0 +; RV32XTHEADBB-NEXT: ret + %icmp = icmp slt i32 %a, %b + %sext = sext i1 %icmp to i32 + ret i32 %sext +} + define i32 @sextb_i32(i32 %a) nounwind { ; RV32I-LABEL: sextb_i32: ; RV32I: # %bb.0: diff --git a/llvm/test/CodeGen/RISCV/rv64xandesperf.ll b/llvm/test/CodeGen/RISCV/rv64xandesperf.ll index 406e5247ae0dd..225495817ae16 100644 --- a/llvm/test/CodeGen/RISCV/rv64xandesperf.ll +++ b/llvm/test/CodeGen/RISCV/rv64xandesperf.ll @@ -290,6 +290,31 @@ define zeroext i8 @sexti1_i32_setcc(i32 signext %a) { ret i8 %sext } +; Make sure we don't use seqz+nds.bfos instead of snez+addi +define signext i32 @sexti1_i32_setcc_2(i32 signext %a, i32 signext %b) { +; CHECK-LABEL: sexti1_i32_setcc_2: +; CHECK: # %bb.0: +; CHECK-NEXT: xor a0, a0, a1 +; CHECK-NEXT: snez a0, a0 +; CHECK-NEXT: addi a0, a0, -1 +; CHECK-NEXT: ret + %icmp = icmp eq i32 %a, %b + %sext = sext i1 %icmp to i32 + ret i32 %sext +} + +; Make sure we don't use nds.bfos instead of neg. +define signext i32 @sexti1_i32_setcc_3(i32 signext %a, i32 signext %b) { +; CHECK-LABEL: sexti1_i32_setcc_3: +; CHECK: # %bb.0: +; CHECK-NEXT: slt a0, a0, a1 +; CHECK-NEXT: neg a0, a0 +; CHECK-NEXT: ret + %icmp = icmp slt i32 %a, %b + %sext = sext i1 %icmp to i32 + ret i32 %sext +} + define signext i32 @sexti8_i32(i32 signext %a) { ; CHECK-LABEL: sexti8_i32: ; CHECK: # %bb.0: @@ -360,6 +385,31 @@ define zeroext i8 @sexti1_i64_setcc(i64 %a) { ret i8 %sext } +; Make sure we don't use seqz+nds.bfos instead of snez+addi +define i64 @sexti1_i64_setcc_2(i64 %a, i64 %b) { +; CHECK-LABEL: sexti1_i64_setcc_2: +; CHECK: # %bb.0: +; CHECK-NEXT: xor a0, a0, a1 +; CHECK-NEXT: snez a0, a0 +; CHECK-NEXT: addi a0, a0, -1 +; CHECK-NEXT: ret + %icmp = icmp eq i64 %a, %b + %sext = sext i1 %icmp to i64 + ret i64 %sext +} + +; Make sure we don't use nds.bfos instead of neg. +define i64 @sexti1_i64_setcc_3(i64 %a, i64 %b) { +; CHECK-LABEL: sexti1_i64_setcc_3: +; CHECK: # %bb.0: +; CHECK-NEXT: slt a0, a0, a1 +; CHECK-NEXT: neg a0, a0 +; CHECK-NEXT: ret + %icmp = icmp slt i64 %a, %b + %sext = sext i1 %icmp to i64 + ret i64 %sext +} + define i64 @sexti8_i64(i64 %a) { ; CHECK-LABEL: sexti8_i64: ; CHECK: # %bb.0: diff --git a/llvm/test/CodeGen/RISCV/rv64xtheadbb.ll b/llvm/test/CodeGen/RISCV/rv64xtheadbb.ll index 92d026b0ef1a5..d7c568bf4e019 100644 --- a/llvm/test/CodeGen/RISCV/rv64xtheadbb.ll +++ b/llvm/test/CodeGen/RISCV/rv64xtheadbb.ll @@ -729,6 +729,44 @@ define zeroext i8 @sexti1_i32_setcc(i32 signext %a) { ret i8 %sext } +; Make sure we don't use seqz+th.ext instead of snez+addi +define signext i32 @sexti1_i32_setcc_2(i32 signext %a, i32 signext %b) { +; RV64I-LABEL: sexti1_i32_setcc_2: +; RV64I: # %bb.0: +; RV64I-NEXT: xor a0, a0, a1 +; RV64I-NEXT: snez a0, a0 +; RV64I-NEXT: addi a0, a0, -1 +; RV64I-NEXT: ret +; +; RV64XTHEADBB-LABEL: sexti1_i32_setcc_2: +; RV64XTHEADBB: # %bb.0: +; RV64XTHEADBB-NEXT: xor a0, a0, a1 +; RV64XTHEADBB-NEXT: snez a0, a0 +; RV64XTHEADBB-NEXT: addi a0, a0, -1 +; RV64XTHEADBB-NEXT: ret + %icmp = icmp eq i32 %a, %b + %sext = sext i1 %icmp to i32 + ret i32 %sext +} + +; Make sure we don't use th.ext instead of neg. +define signext i32 @sexti1_i32_setcc_3(i32 signext %a, i32 signext %b) { +; RV64I-LABEL: sexti1_i32_setcc_3: +; RV64I: # %bb.0: +; RV64I-NEXT: slt a0, a0, a1 +; RV64I-NEXT: neg a0, a0 +; RV64I-NEXT: ret +; +; RV64XTHEADBB-LABEL: sexti1_i32_setcc_3: +; RV64XTHEADBB: # %bb.0: +; RV64XTHEADBB-NEXT: slt a0, a0, a1 +; RV64XTHEADBB-NEXT: neg a0, a0 +; RV64XTHEADBB-NEXT: ret + %icmp = icmp slt i32 %a, %b + %sext = sext i1 %icmp to i32 + ret i32 %sext +} + define i64 @sexti1_i64(i64 %a) nounwind { ; RV64I-LABEL: sexti1_i64: ; RV64I: # %bb.0: @@ -780,6 +818,44 @@ define zeroext i8 @sexti1_i64_setcc(i64 %a) { ret i8 %sext } +; Make sure we don't use seqz+th.ext instead of snez+addi +define i64 @sexti1_i64_setcc_2(i64 %a, i64 %b) { +; RV64I-LABEL: sexti1_i64_setcc_2: +; RV64I: # %bb.0: +; RV64I-NEXT: xor a0, a0, a1 +; RV64I-NEXT: snez a0, a0 +; RV64I-NEXT: addi a0, a0, -1 +; RV64I-NEXT: ret +; +; RV64XTHEADBB-LABEL: sexti1_i64_setcc_2: +; RV64XTHEADBB: # %bb.0: +; RV64XTHEADBB-NEXT: xor a0, a0, a1 +; RV64XTHEADBB-NEXT: snez a0, a0 +; RV64XTHEADBB-NEXT: addi a0, a0, -1 +; RV64XTHEADBB-NEXT: ret + %icmp = icmp eq i64 %a, %b + %sext = sext i1 %icmp to i64 + ret i64 %sext +} + +; Make sure we don't use th.ext instead of neg. +define i64 @sexti1_i64_setcc_3(i64 %a, i64 %b) { +; RV64I-LABEL: sexti1_i64_setcc_3: +; RV64I: # %bb.0: +; RV64I-NEXT: slt a0, a0, a1 +; RV64I-NEXT: neg a0, a0 +; RV64I-NEXT: ret +; +; RV64XTHEADBB-LABEL: sexti1_i64_setcc_3: +; RV64XTHEADBB: # %bb.0: +; RV64XTHEADBB-NEXT: slt a0, a0, a1 +; RV64XTHEADBB-NEXT: neg a0, a0 +; RV64XTHEADBB-NEXT: ret + %icmp = icmp slt i64 %a, %b + %sext = sext i1 %icmp to i64 + ret i64 %sext +} + define signext i32 @sextb_i32(i32 signext %a) nounwind { ; RV64I-LABEL: sextb_i32: ; RV64I: # %bb.0: diff --git a/llvm/test/CodeGen/RISCV/xqcibm-extract.ll b/llvm/test/CodeGen/RISCV/xqcibm-extract.ll index fc3d8fe54602a..c2c9d077b2526 100644 --- a/llvm/test/CodeGen/RISCV/xqcibm-extract.ll +++ b/llvm/test/CodeGen/RISCV/xqcibm-extract.ll @@ -74,6 +74,56 @@ define zeroext i8 @sexti1_i32_setcc(i32 signext %a) { ret i8 %sext } +; Make sure we don't use seqz+qc.ext instead of snez+addi +define i32 @sexti1_i32_setcc_2(i32 %a, i32 %b) { +; RV32I-LABEL: sexti1_i32_setcc_2: +; RV32I: # %bb.0: +; RV32I-NEXT: xor a0, a0, a1 +; RV32I-NEXT: snez a0, a0 +; RV32I-NEXT: addi a0, a0, -1 +; RV32I-NEXT: ret +; +; RV32XQCIBM-LABEL: sexti1_i32_setcc_2: +; RV32XQCIBM: # %bb.0: +; RV32XQCIBM-NEXT: xor a0, a0, a1 +; RV32XQCIBM-NEXT: snez a0, a0 +; RV32XQCIBM-NEXT: addi a0, a0, -1 +; RV32XQCIBM-NEXT: ret +; +; RV32XQCIBMZBB-LABEL: sexti1_i32_setcc_2: +; RV32XQCIBMZBB: # %bb.0: +; RV32XQCIBMZBB-NEXT: xor a0, a0, a1 +; RV32XQCIBMZBB-NEXT: snez a0, a0 +; RV32XQCIBMZBB-NEXT: addi a0, a0, -1 +; RV32XQCIBMZBB-NEXT: ret + %icmp = icmp eq i32 %a, %b + %sext = sext i1 %icmp to i32 + ret i32 %sext +} + +; Make sure we don't use qc.ext instead of neg. +define i32 @sexti1_i32_setcc_3(i32 %a, i32 %b) { +; RV32I-LABEL: sexti1_i32_setcc_3: +; RV32I: # %bb.0: +; RV32I-NEXT: slt a0, a0, a1 +; RV32I-NEXT: neg a0, a0 +; RV32I-NEXT: ret +; +; RV32XQCIBM-LABEL: sexti1_i32_setcc_3: +; RV32XQCIBM: # %bb.0: +; RV32XQCIBM-NEXT: slt a0, a0, a1 +; RV32XQCIBM-NEXT: neg a0, a0 +; RV32XQCIBM-NEXT: ret +; +; RV32XQCIBMZBB-LABEL: sexti1_i32_setcc_3: +; RV32XQCIBMZBB: # %bb.0: +; RV32XQCIBMZBB-NEXT: slt a0, a0, a1 +; RV32XQCIBMZBB-NEXT: neg a0, a0 +; RV32XQCIBMZBB-NEXT: ret + %icmp = icmp slt i32 %a, %b + %sext = sext i1 %icmp to i32 + ret i32 %sext +} define i32 @sexti8_i32(i8 %a) nounwind { ; RV32I-LABEL: sexti8_i32: