[llvm] 067add7 - [RISCV] Support vmsge.vx and vmsgeu.vx pseudo instructions in RVV.
Hsiangkai Wang via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 2 02:21:24 PDT 2020
Author: Hsiangkai Wang
Date: 2020-10-02T17:20:34+08:00
New Revision: 067add7b5fd22c879bd2bbf5d55f4fb9b63047bf
URL: https://github.com/llvm/llvm-project/commit/067add7b5fd22c879bd2bbf5d55f4fb9b63047bf
DIFF: https://github.com/llvm/llvm-project/commit/067add7b5fd22c879bd2bbf5d55f4fb9b63047bf.diff
LOG: [RISCV] Support vmsge.vx and vmsgeu.vx pseudo instructions in RVV.
Implement vmsge{u}.vx pseudo instruction.
According to RISC-V V specification, there are different scenarios for this
pseudo instruction. I list them below.
unmasked va >= x
pseudoinstruction: vmsge{u}.vx vd, va, x
expansion: vmslt{u}.vx vd, va, x; vmnand.mm vd, vd, vd
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
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
Use pseudo instruction to model vmsge{u}.vx. The pseudo instruction will convert
to different expansion according to the condition.
Differential Revision: https://reviews.llvm.org/D84732
Added:
Modified:
llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
llvm/lib/Target/RISCV/RISCVInstrInfoV.td
llvm/lib/Target/RISCV/RISCVRegisterInfo.td
llvm/test/MC/RISCV/rvv/compare.s
llvm/test/MC/RISCV/rvv/invalid.s
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index 5898149c9fe1..8e0698966d05 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -61,6 +61,10 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ void expandVMSGE(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &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 @@ void RISCVMCCodeEmitter::expandAddTPRel(const MCInst &MI, raw_ostream &OS,
support::endian::write(OS, Binary, support::little);
}
+void RISCVMCCodeEmitter::expandVMSGE(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &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<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
@@ -216,6 +306,16 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
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
index 3ac474cb6549..f0c9fcae9711 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoV.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoV.td
@@ -629,6 +629,46 @@ def : InstAlias<"vmsge.vi $vd, $va, $imm$vm",
(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
index 7544b4b3b845..2b44847104a0 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
@@ -296,7 +296,7 @@ class RegisterTypes<list<ValueType> reg_types> {
// 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 @@ def VR : RegisterClass<"RISCV", [nxv8i8, nxv4i16, nxv2i32, nxv1i64],
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
index f93aeac1796a..6b5eb213d0ec 100644
--- 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 @@ vmsge.vi v8, v4, 16
# CHECK-ENCODING: [0x57,0xb4,0x47,0x7e]
# CHECK-ERROR: instruction requires the following: 'V' (Vector Instructions)
# CHECK-UNKNOWN: 57 b4 47 7e <unknown>
+
+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 <unknown>
+# CHECK-UNKNOWN: 57 24 84 76 <unknown>
+
+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 <unknown>
+# CHECK-UNKNOWN: 57 20 00 76 <unknown>
+
+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 <unknown>
+# CHECK-UNKNOWN: 57 24 84 76 <unknown>
+
+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 <unknown>
+# CHECK-UNKNOWN: 57 24 80 6e <unknown>
+
+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 <unknown>
+# CHECK-UNKNOWN: 57 24 80 6e <unknown>
+
+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 <unknown>
+# CHECK-UNKNOWN: 57 20 01 62 <unknown>
+
+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 <unknown>
+# CHECK-UNKNOWN: 57 20 01 62 <unknown>
diff --git a/llvm/test/MC/RISCV/rvv/invalid.s b/llvm/test/MC/RISCV/rvv/invalid.s
index 615dc08ad67c..79b4ea62f665 100644
--- a/llvm/test/MC/RISCV/rvv/invalid.s
+++ b/llvm/test/MC/RISCV/rvv/invalid.s
@@ -590,3 +590,11 @@ vadd.vx v0, v2, a0, v0.t
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
More information about the llvm-commits
mailing list