diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -61,6 +61,10 @@ SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + void expandVMSGE(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + /// TableGen'erated function for getting the binary encoding for an /// instruction. uint64_t getBinaryCodeForInstr(const MCInst &MI, @@ -188,6 +192,92 @@ support::endian::write(OS, Binary, support::little); } +void RISCVMCCodeEmitter::expandVMSGE(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + MCInst TmpInst; + uint32_t Binary; + unsigned Opcode; + switch (MI.getOpcode()) { + default: + llvm_unreachable("Unexpacted opcode. It should be vmsgeu.vx or vmsge.vx."); + case RISCV::PseudoVMSGEU_VX: + case RISCV::PseudoVMSGEU_VX_M: + case RISCV::PseudoVMSGEU_VX_M_T: + Opcode = RISCV::VMSLTU_VX; + break; + case RISCV::PseudoVMSGE_VX: + case RISCV::PseudoVMSGE_VX_M: + case RISCV::PseudoVMSGE_VX_M_T: + Opcode = RISCV::VMSLT_VX; + break; + } + if (MI.getNumOperands() == 3) { + // unmasked va >= x + // + // pseudoinstruction: vmsge{u}.vx vd, va, x + // expansion: vmslt{u}.vx vd, va, x; vmnand.mm vd, vd, vd + TmpInst = MCInstBuilder(Opcode) + .addOperand(MI.getOperand(0)) + .addOperand(MI.getOperand(1)) + .addOperand(MI.getOperand(2)) + .addReg(RISCV::NoRegister); + Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); + support::endian::write(OS, Binary, support::little); + + TmpInst = MCInstBuilder(RISCV::VMNAND_MM) + .addOperand(MI.getOperand(0)) + .addOperand(MI.getOperand(0)) + .addOperand(MI.getOperand(0)); + Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); + support::endian::write(OS, Binary, support::little); + } else if (MI.getNumOperands() == 4) { + // masked va >= x, vd != v0 + // + // pseudoinstruction: vmsge{u}.vx vd, va, x, v0.t + // expansion: vmslt{u}.vx vd, va, x, v0.t; vmxor.mm vd, vd, v0 + assert(MI.getOperand(0).getReg() != RISCV::V0 && + "The destination register should not be V0."); + TmpInst = MCInstBuilder(Opcode) + .addOperand(MI.getOperand(0)) + .addOperand(MI.getOperand(1)) + .addOperand(MI.getOperand(2)) + .addOperand(MI.getOperand(3)); + Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); + support::endian::write(OS, Binary, support::little); + + TmpInst = MCInstBuilder(RISCV::VMXOR_MM) + .addOperand(MI.getOperand(0)) + .addOperand(MI.getOperand(0)) + .addReg(RISCV::V0); + Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); + support::endian::write(OS, Binary, support::little); + } else if (MI.getNumOperands() == 5) { + // masked va >= x, vd == v0 + // + // pseudoinstruction: vmsge{u}.vx vd, va, x, v0.t, vt + // expansion: vmslt{u}.vx vt, va, x; vmandnot.mm vd, vd, vt + assert(MI.getOperand(0).getReg() == RISCV::V0 && + "The destination register should be V0."); + assert(MI.getOperand(1).getReg() != RISCV::V0 && + "The temporary vector register should not be V0."); + TmpInst = MCInstBuilder(Opcode) + .addOperand(MI.getOperand(1)) + .addOperand(MI.getOperand(2)) + .addOperand(MI.getOperand(3)) + .addOperand(MI.getOperand(4)); + Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); + support::endian::write(OS, Binary, support::little); + + TmpInst = MCInstBuilder(RISCV::VMANDNOT_MM) + .addOperand(MI.getOperand(0)) + .addOperand(MI.getOperand(0)) + .addOperand(MI.getOperand(1)); + Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI); + support::endian::write(OS, Binary, support::little); + } +} + void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { @@ -216,6 +306,16 @@ return; } + if (MI.getOpcode() == RISCV::PseudoVMSGEU_VX || + MI.getOpcode() == RISCV::PseudoVMSGE_VX || + MI.getOpcode() == RISCV::PseudoVMSGEU_VX_M || + MI.getOpcode() == RISCV::PseudoVMSGE_VX_M || + MI.getOpcode() == RISCV::PseudoVMSGEU_VX_M_T || + MI.getOpcode() == RISCV::PseudoVMSGE_VX_M_T) { + expandVMSGE(MI, OS, Fixups, STI); + return; + } + switch (Size) { default: llvm_unreachable("Unhandled encodeInstruction length!"); diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoV.td b/llvm/lib/Target/RISCV/RISCVInstrInfoV.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoV.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoV.td @@ -629,6 +629,46 @@ (VMSGT_VI VRegOp:$vd, VRegOp:$va, simm5_plus1:$imm, VMaskOp:$vm), 0>; +let isAsmParserOnly = 1, hasSideEffects = 0, mayLoad = 0, mayStore = 0 in { +def PseudoVMSGEU_VX : Pseudo<(outs VRegOp:$vd), + (ins VRegOp:$vs2, GPR:$rs1), + [], "vmsgeu.vx", "$vd, $vs2, $rs1">; +def PseudoVMSGE_VX : Pseudo<(outs VRegOp:$vd), + (ins VRegOp:$vs2, GPR:$rs1), + [], "vmsge.vx", "$vd, $vs2, $rs1">; +def PseudoVMSGEU_VX_M : Pseudo<(outs VRNoV0:$vd), + (ins VRegOp:$vs2, GPR:$rs1, VMaskOp:$vm), + [], "vmsgeu.vx", "$vd, $vs2, $rs1$vm">; +def PseudoVMSGE_VX_M : Pseudo<(outs VRNoV0:$vd), + (ins VRegOp:$vs2, GPR:$rs1, VMaskOp:$vm), + [], "vmsge.vx", "$vd, $vs2, $rs1$vm">; +def PseudoVMSGEU_VX_M_T : Pseudo<(outs VMV0:$vd, VRegOp:$scratch), + (ins VRegOp:$vs2, GPR:$rs1, VMaskOp:$vm), + [], "vmsgeu.vx", "$vd, $vs2, $rs1$vm, $scratch">; +def PseudoVMSGE_VX_M_T : Pseudo<(outs VMV0:$vd, VRegOp:$scratch), + (ins VRegOp:$vs2, GPR:$rs1, VMaskOp:$vm), + [], "vmsge.vx", "$vd, $vs2, $rs1$vm, $scratch">; +} + +// This apparently unnecessary alias prevents matching `vmsge{u}.vx vd, vs2, vs1` as if +// it were an unmasked (i.e. $vm = RISCV::NoRegister) PseudoVMSGE{U}_VX_M. +def : InstAlias<"vmsgeu.vx $vd, $va, $rs1", + (PseudoVMSGEU_VX VRegOp:$vd, VRegOp:$va, GPR:$rs1), 0>; +def : InstAlias<"vmsge.vx $vd, $va, $rs1", + (PseudoVMSGE_VX VRegOp:$vd, VRegOp:$va, GPR:$rs1), 0>; +def : InstAlias<"vmsgeu.vx v0, $va, $rs1, $vm, $vt", + (PseudoVMSGEU_VX_M_T V0, VRegOp:$vt, VRegOp:$va, GPR:$rs1, + VMaskOp:$vm), 0>; +def : InstAlias<"vmsge.vx v0, $va, $rs1, $vm, $vt", + (PseudoVMSGE_VX_M_T V0, VRegOp:$vt, VRegOp:$va, GPR:$rs1, + VMaskOp:$vm), 0>; +def : InstAlias<"vmsgeu.vx $vd, $va, $rs1, $vm", + (PseudoVMSGEU_VX_M VRNoV0:$vd, VRegOp:$va, GPR:$rs1, + VMaskOp:$vm), 0>; +def : InstAlias<"vmsge.vx $vd, $va, $rs1, $vm", + (PseudoVMSGE_VX_M VRNoV0:$vd, VRegOp:$va, GPR:$rs1, + VMaskOp:$vm), 0>; + // Vector Integer Min/Max Instructions defm VMINU_V : VALU_IV_V_X<"vminu", 0b000100>; defm VMIN_V : VALU_IV_V_X<"vmin", 0b000101>; diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td @@ -296,7 +296,7 @@ // The order of registers represents the preferred allocation sequence, // meaning caller-save regs are listed before callee-save. def VR : RegisterClass<"RISCV", [nxv8i8, nxv4i16, nxv2i32, nxv1i64], - 64, (add + 64, (add (sequence "V%u", 25, 31), (sequence "V%u", 8, 24), (sequence "V%u", 0, 7) @@ -304,6 +304,15 @@ let Size = 64; } +def VRNoV0 : RegisterClass<"RISCV", [nxv8i8, nxv4i16, nxv2i32, nxv1i64], + 64, (add + (sequence "V%u", 25, 31), + (sequence "V%u", 8, 24), + (sequence "V%u", 1, 7) + )> { + let Size = 64; +} + def VRM2 : RegisterClass<"RISCV", [nxv16i8, nxv8i16, nxv4i32, nxv2i64], 64, (add V26M2, V28M2, V30M2, V8M2, V10M2, V12M2, V14M2, V16M2, V18M2, V20M2, V22M2, V24M2, V0M2, V2M2, V4M2, V6M2)> { diff --git a/llvm/test/MC/RISCV/rvv/compare.s b/llvm/test/MC/RISCV/rvv/compare.s --- a/llvm/test/MC/RISCV/rvv/compare.s +++ b/llvm/test/MC/RISCV/rvv/compare.s @@ -1,5 +1,5 @@ # RUN: llvm-mc -triple=riscv64 -show-encoding --mattr=+experimental-v %s \ -# RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST +# RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING # RUN: not llvm-mc -triple=riscv64 -show-encoding %s 2>&1 \ # RUN: | FileCheck %s --check-prefix=CHECK-ERROR # RUN: llvm-mc -triple=riscv64 -filetype=obj --mattr=+experimental-v %s \ @@ -349,3 +349,59 @@ # CHECK-ENCODING: [0x57,0xb4,0x47,0x7e] # CHECK-ERROR: instruction requires the following: 'V' (Vector Instructions) # CHECK-UNKNOWN: 57 b4 47 7e + +vmsgeu.vx v8, v4, a0 +# CHECK-INST: vmsltu.vx v8, v4, a0 +# CHECK-INST: vmnot.m v8, v8 +# CHECK-ENCODING: [0x57,0x44,0x45,0x6a,0x57,0x24,0x84,0x76] +# CHECK-ERROR: instruction requires the following: 'V' (Vector Instructions) +# CHECK-UNKNOWN: 57 44 45 6a +# CHECK-UNKNOWN: 57 24 84 76 + +vmsge.vx v0, v4, a0 +# CHECK-INST: vmslt.vx v0, v4, a0 +# CHECK-INST: vmnot.m v0, v0 +# CHECK-ENCODING: [0x57,0x40,0x45,0x6e,0x57,0x20,0x00,0x76] +# CHECK-ERROR: instruction requires the following: 'V' (Vector Instructions) +# CHECK-UNKNOWN: 57 40 45 6e +# CHECK-UNKNOWN: 57 20 00 76 + +vmsge.vx v8, v4, a0 +# CHECK-INST: vmslt.vx v8, v4, a0 +# CHECK-INST: vmnot.m v8, v8 +# CHECK-ENCODING: [0x57,0x44,0x45,0x6e,0x57,0x24,0x84,0x76] +# CHECK-ERROR: instruction requires the following: 'V' (Vector Instructions) +# CHECK-UNKNOWN: 57 44 45 6e +# CHECK-UNKNOWN: 57 24 84 76 + +vmsgeu.vx v8, v4, a0, v0.t +# CHECK-INST: vmsltu.vx v8, v4, a0, v0.t +# CHECK-INST: vmxor.mm v8, v8, v0 +# CHECK-ENCODING: [0x57,0x44,0x45,0x68,0x57,0x24,0x80,0x6e] +# CHECK-ERROR: instruction requires the following: 'V' (Vector Instructions) +# CHECK-UNKNOWN: 57 44 45 68 +# CHECK-UNKNOWN: 57 24 80 6e + +vmsge.vx v8, v4, a0, v0.t +# CHECK-INST: vmslt.vx v8, v4, a0, v0.t +# CHECK-INST: vmxor.mm v8, v8, v0 +# CHECK-ENCODING: [0x57,0x44,0x45,0x6c,0x57,0x24,0x80,0x6e] +# CHECK-ERROR: instruction requires the following: 'V' (Vector Instructions) +# CHECK-UNKNOWN: 57 44 45 6c +# CHECK-UNKNOWN: 57 24 80 6e + +vmsgeu.vx v0, v4, a0, v0.t, v2 +# CHECK-INST: vmsltu.vx v2, v4, a0, v0.t +# CHECK-INST: vmandnot.mm v0, v0, v2 +# CHECK-ENCODING: [0x57,0x41,0x45,0x68,0x57,0x20,0x01,0x62] +# CHECK-ERROR: instruction requires the following: 'V' (Vector Instructions) +# CHECK-UNKNOWN: 57 41 45 68 +# CHECK-UNKNOWN: 57 20 01 62 + +vmsge.vx v0, v4, a0, v0.t, v2 +# CHECK-INST: vmslt.vx v2, v4, a0, v0.t +# CHECK-INST: vmandnot.mm v0, v0, v2 +# CHECK-ENCODING: [0x57,0x41,0x45,0x6c,0x57,0x20,0x01,0x62] +# CHECK-ERROR: instruction requires the following: 'V' (Vector Instructions) +# CHECK-UNKNOWN: 57 41 45 6c +# CHECK-UNKNOWN: 57 20 01 62 diff --git a/llvm/test/MC/RISCV/rvv/invalid.s b/llvm/test/MC/RISCV/rvv/invalid.s --- a/llvm/test/MC/RISCV/rvv/invalid.s +++ b/llvm/test/MC/RISCV/rvv/invalid.s @@ -590,3 +590,11 @@ vadd.vi v0, v2, 1, v0.t # CHECK-ERROR: The destination vector register group cannot overlap the mask register. # CHECK-ERROR-LABEL: vadd.vi v0, v2, 1, v0.t + +vmsge.vx v0, v4, a0, v0.t +# CHECK-ERROR: too few operands for instruction +# CHECK-ERROR-LABEL: vmsge.vx v0, v4, a0, v0.t + +vmsge.vx v8, v4, a0, v0.t, v2 +# CHECK-ERROR: invalid operand for instruction +# CHECK-ERROR-LABEL: vmsge.vx v8, v4, a0, v0.t, v2