diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp index 17b617c502ca9..76ff0c3be2a0f 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -1616,21 +1616,28 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) { SDValue Src1 = Node->getOperand(1); SDValue Src2 = Node->getOperand(2); bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu; - bool IsCmpUnsignedZero = false; + bool IsCmpConstant = false; + bool IsCmpMinimum = false; // Only custom select scalar second operand. if (Src2.getValueType() != XLenVT) break; // Small constants are handled with patterns. + int64_t CVal = 0; + MVT Src1VT = Src1.getSimpleValueType(); if (auto *C = dyn_cast(Src2)) { - int64_t CVal = C->getSExtValue(); + IsCmpConstant = true; + CVal = C->getSExtValue(); if (CVal >= -15 && CVal <= 16) { if (!IsUnsigned || CVal != 0) break; - IsCmpUnsignedZero = true; + IsCmpMinimum = true; + } else if (!IsUnsigned && CVal == APInt::getSignedMinValue( + Src1VT.getScalarSizeInBits()) + .getSExtValue()) { + IsCmpMinimum = true; } } - MVT Src1VT = Src1.getSimpleValueType(); - unsigned VMSLTOpcode, VMNANDOpcode, VMSetOpcode; + unsigned VMSLTOpcode, VMNANDOpcode, VMSetOpcode, VMSGTOpcode; switch (RISCVTargetLowering::getLMUL(Src1VT)) { default: llvm_unreachable("Unexpected LMUL!"); @@ -1638,6 +1645,8 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) { case RISCVII::VLMUL::lmulenum: \ VMSLTOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix \ : RISCV::PseudoVMSLT_VX_##suffix; \ + VMSGTOpcode = IsUnsigned ? RISCV::PseudoVMSGTU_VX_##suffix \ + : RISCV::PseudoVMSGT_VX_##suffix; \ VMNANDOpcode = RISCV::PseudoVMNAND_MM_##suffix; \ VMSetOpcode = RISCV::PseudoVMSET_M_##suffix_b; \ break; @@ -1655,12 +1664,21 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) { SDValue VL; selectVLOp(Node->getOperand(3), VL); - // If vmsgeu with 0 immediate, expand it to vmset. - if (IsCmpUnsignedZero) { + // If vmsge(u) with minimum value, expand it to vmset. + if (IsCmpMinimum) { ReplaceNode(Node, CurDAG->getMachineNode(VMSetOpcode, DL, VT, VL, SEW)); return; } + if (IsCmpConstant) { + SDValue Imm = + selectImm(CurDAG, SDLoc(Src2), XLenVT, CVal - 1, *Subtarget); + + ReplaceNode(Node, CurDAG->getMachineNode(VMSGTOpcode, DL, VT, + {Src1, Imm, VL, SEW})); + return; + } + // Expand to // vmslt{u}.vx vd, va, x; vmnand.mm vd, vd, vd SDValue Cmp = SDValue( @@ -1675,22 +1693,29 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) { SDValue Src1 = Node->getOperand(2); SDValue Src2 = Node->getOperand(3); bool IsUnsigned = IntNo == Intrinsic::riscv_vmsgeu_mask; - bool IsCmpUnsignedZero = false; + bool IsCmpConstant = false; + bool IsCmpMinimum = false; // Only custom select scalar second operand. if (Src2.getValueType() != XLenVT) break; // Small constants are handled with patterns. + MVT Src1VT = Src1.getSimpleValueType(); + int64_t CVal = 0; if (auto *C = dyn_cast(Src2)) { - int64_t CVal = C->getSExtValue(); + IsCmpConstant = true; + CVal = C->getSExtValue(); if (CVal >= -15 && CVal <= 16) { if (!IsUnsigned || CVal != 0) break; - IsCmpUnsignedZero = true; + IsCmpMinimum = true; + } else if (!IsUnsigned && CVal == APInt::getSignedMinValue( + Src1VT.getScalarSizeInBits()) + .getSExtValue()) { + IsCmpMinimum = true; } } - MVT Src1VT = Src1.getSimpleValueType(); unsigned VMSLTOpcode, VMSLTMaskOpcode, VMXOROpcode, VMANDNOpcode, - VMOROpcode; + VMOROpcode, VMSGTMaskOpcode; switch (RISCVTargetLowering::getLMUL(Src1VT)) { default: llvm_unreachable("Unexpected LMUL!"); @@ -1700,6 +1725,8 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) { : RISCV::PseudoVMSLT_VX_##suffix; \ VMSLTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSLTU_VX_##suffix##_MASK \ : RISCV::PseudoVMSLT_VX_##suffix##_MASK; \ + VMSGTMaskOpcode = IsUnsigned ? RISCV::PseudoVMSGTU_VX_##suffix##_MASK \ + : RISCV::PseudoVMSGT_VX_##suffix##_MASK; \ break; CASE_VMSLT_OPCODES(LMUL_F8, MF8, B1) CASE_VMSLT_OPCODES(LMUL_F4, MF4, B2) @@ -1737,8 +1764,8 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) { SDValue MaskedOff = Node->getOperand(1); SDValue Mask = Node->getOperand(4); - // If vmsgeu_mask with 0 immediate, expand it to vmor mask, maskedoff. - if (IsCmpUnsignedZero) { + // If vmsge(u) with minimum value, expand it to vmor mask, maskedoff. + if (IsCmpMinimum) { // We don't need vmor if the MaskedOff and the Mask are the same // value. if (Mask == MaskedOff) { @@ -1769,6 +1796,16 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) { SDValue Glue = Chain.getValue(1); SDValue V0 = CurDAG->getRegister(RISCV::V0, VT); + if (IsCmpConstant) { + SDValue Imm = + selectImm(CurDAG, SDLoc(Src2), XLenVT, CVal - 1, *Subtarget); + + ReplaceNode(Node, CurDAG->getMachineNode( + VMSGTMaskOpcode, DL, VT, + {MaskedOff, Src1, Imm, V0, VL, SEW, Glue})); + return; + } + // Otherwise use // vmslt{u}.vx vd, va, x, v0.t; vmxor.mm vd, vd, v0 // The result is mask undisturbed. diff --git a/llvm/test/CodeGen/RISCV/rvv/vmsge.ll b/llvm/test/CodeGen/RISCV/rvv/vmsge.ll index 1ec304609699a..e6d775dee5b22 100644 --- a/llvm/test/CodeGen/RISCV/rvv/vmsge.ll +++ b/llvm/test/CodeGen/RISCV/rvv/vmsge.ll @@ -1084,6 +1084,45 @@ entry: ret %a } +define @intrinsic_vmsge_mask_vx_nxv4i8_i8_1( %0, %1, %2, iXLen %3) nounwind { +; CHECK-LABEL: intrinsic_vmsge_mask_vx_nxv4i8_i8_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v10, v0 +; CHECK-NEXT: li a1, 99 +; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vsetvli zero, a0, e8, mf2, ta, mu +; CHECK-NEXT: vmsgt.vx v10, v8, a1, v0.t +; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: ret +entry: + %a = call @llvm.riscv.vmsge.mask.nxv4i8.i8( + %0, + %1, + i8 100, + %2, + iXLen %3) + + ret %a +} + +define @intrinsic_vmsge_mask_vx_nxv4i8_i8_2( %0, %1, %2, iXLen %3) nounwind { +; CHECK-LABEL: intrinsic_vmsge_mask_vx_nxv4i8_i8_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vsetvli zero, a0, e8, mf2, ta, ma +; CHECK-NEXT: vmor.mm v0, v9, v0 +; CHECK-NEXT: ret +entry: + %a = call @llvm.riscv.vmsge.mask.nxv4i8.i8( + %0, + %1, + i8 -128, + %2, + iXLen %3) + + ret %a +} + + declare @llvm.riscv.vmsge.nxv8i8.i8( , i8, @@ -1970,6 +2009,37 @@ entry: ret %a } +define @intrinsic_vmsge_vi_nxv4i8_i8_1( %0, iXLen %1) nounwind { +; CHECK-LABEL: intrinsic_vmsge_vi_nxv4i8_i8_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li a1, 99 +; CHECK-NEXT: vsetvli zero, a0, e8, mf2, ta, ma +; CHECK-NEXT: vmsgt.vx v0, v8, a1 +; CHECK-NEXT: ret +entry: + %a = call @llvm.riscv.vmsge.nxv4i8.i8( + %0, + i8 100, + iXLen %1) + + ret %a +} + +define @intrinsic_vmsge_vi_nxv4i8_i8_2( %0, iXLen %1) nounwind { +; CHECK-LABEL: intrinsic_vmsge_vi_nxv4i8_i8_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vsetvli zero, a0, e8, mf2, ta, ma +; CHECK-NEXT: vmset.m v0 +; CHECK-NEXT: ret +entry: + %a = call @llvm.riscv.vmsge.nxv4i8.i8( + %0, + i8 -128, + iXLen %1) + + ret %a +} + define @intrinsic_vmsge_mask_vi_nxv4i8_i8( %0, %1, %2, iXLen %3) nounwind { ; CHECK-LABEL: intrinsic_vmsge_mask_vi_nxv4i8_i8: ; CHECK: # %bb.0: # %entry diff --git a/llvm/test/CodeGen/RISCV/rvv/vmsgeu.ll b/llvm/test/CodeGen/RISCV/rvv/vmsgeu.ll index 05cc7a9d8f7b4..68aa912ae42ea 100644 --- a/llvm/test/CodeGen/RISCV/rvv/vmsgeu.ll +++ b/llvm/test/CodeGen/RISCV/rvv/vmsgeu.ll @@ -1990,6 +1990,27 @@ entry: ret %a } +define @intrinsic_vmsgeu_mask_vi_nxv4i8_i8_1( %0, %1, %2, iXLen %3) nounwind { +; CHECK-LABEL: intrinsic_vmsgeu_mask_vi_nxv4i8_i8_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v10, v0 +; CHECK-NEXT: li a1, 99 +; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vsetvli zero, a0, e8, mf2, ta, mu +; CHECK-NEXT: vmsgtu.vx v10, v8, a1, v0.t +; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: ret +entry: + %a = call @llvm.riscv.vmsgeu.mask.nxv4i8.i8( + %0, + %1, + i8 100, + %2, + iXLen %3) + + ret %a +} + define @intrinsic_vmsgeu_vi_nxv8i8_i8( %0, iXLen %1) nounwind { ; CHECK-LABEL: intrinsic_vmsgeu_vi_nxv8i8_i8: ; CHECK: # %bb.0: # %entry @@ -2192,6 +2213,22 @@ entry: ret %a } +define @intrinsic_vmsgeu_vi_nxv4i16_i16_1( %0, iXLen %1) nounwind { +; CHECK-LABEL: intrinsic_vmsgeu_vi_nxv4i16_i16_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: li a1, 99 +; CHECK-NEXT: vsetvli zero, a0, e16, m1, ta, ma +; CHECK-NEXT: vmsgtu.vx v0, v8, a1 +; CHECK-NEXT: ret +entry: + %a = call @llvm.riscv.vmsgeu.nxv4i16.i16( + %0, + i16 100, + iXLen %1) + + ret %a +} + define @intrinsic_vmsgeu_mask_vi_nxv4i16_i16( %0, %1, %2, iXLen %3) nounwind { ; CHECK-LABEL: intrinsic_vmsgeu_mask_vi_nxv4i16_i16: ; CHECK: # %bb.0: # %entry