[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