[llvm] [RISCV] Make All VType Parts Optional (PR #144971)

Sam Elliott via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 19 19:30:09 PDT 2025


https://github.com/lenary created https://github.com/llvm/llvm-project/pull/144971

This matches the current binutils behaviour, and the orignal ratified spec that states that LMUL=1 when the lmul operand is omitted. A variety of previously invalid vtype instructions are now accepted by the assembler.

To match binutils, at least one of the vtype operands must be provided.

Also fixes the MCOperandPredicate definition in VTypeIOp, which had one logic issue and one syntax issue. This is not used by the MC layer currently, so this change should not affect the existing implementation.

Fixes #143744

>From 4c0edf6ae67b407dafef861f75efe638ed52ead9 Mon Sep 17 00:00:00 2001
From: Sam Elliott <quic_aelliott at quicinc.com>
Date: Thu, 19 Jun 2025 19:09:40 -0700
Subject: [PATCH] [RISCV] Make All VType Parts Optional

This matches the current binutils behaviour, and the orignal ratified
spec that states that LMUL=1 when the lmul operand is omitted. A variety
of previously invalid vtype instructions are now accepted by the
assembler.

To match binutils, at least one of the vtype operands must be provided.

Also fixes the MCOperandPredicate definition in VTypeIOp, which had one
logic issue and one syntax issue. This is not used by the MC layer
currently, so this change should not affect the existing implementation.

Fixes #143744
---
 .../Target/RISCV/AsmParser/RISCVAsmParser.cpp | 128 +++++++++---------
 llvm/lib/Target/RISCV/RISCVInstrInfoV.td      |   4 +-
 llvm/test/MC/RISCV/rvv/invalid.s              |  28 +---
 llvm/test/MC/RISCV/rvv/vsetvl.s               |  62 ++++++++-
 4 files changed, 130 insertions(+), 92 deletions(-)

diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index f1d6f99ba9815..dd7b098fca1c4 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -66,16 +66,14 @@ struct ParserOptionsSet {
 };
 
 class RISCVAsmParser : public MCTargetAsmParser {
-  // This tracks the parsing of the 4 operands that make up the vtype portion
-  // of vset(i)vli instructions which are separated by commas. The state names
-  // represent the next expected operand with Done meaning no other operands are
-  // expected.
-  enum VTypeState {
-    VTypeState_SEW,
-    VTypeState_LMUL,
-    VTypeState_TailPolicy,
-    VTypeState_MaskPolicy,
-    VTypeState_Done,
+  // This tracks the parsing of the 4 optional operands that make up the vtype
+  // portion of vset(i)vli instructions which are separated by commas.
+  enum class VTypeState {
+    SeenNothingYet,
+    SeenSew,
+    SeenLmul,
+    SeenTailPolicy,
+    SeenMaskPolicy,
   };
 
   SmallVector<FeatureBitset, 4> FeatureBitStack;
@@ -2233,25 +2231,30 @@ bool RISCVAsmParser::parseVTypeToken(const AsmToken &Tok, VTypeState &State,
     return true;
 
   StringRef Identifier = Tok.getIdentifier();
-
-  switch (State) {
-  case VTypeState_SEW:
-    if (!Identifier.consume_front("e"))
-      break;
+  if (State < VTypeState::SeenSew && Identifier.consume_front("e")) {
     if (Identifier.getAsInteger(10, Sew))
-      break;
+      return true;
     if (!RISCVVType::isValidSEW(Sew))
-      break;
-    State = VTypeState_LMUL;
+      return true;
+
+    State = VTypeState::SeenSew;
     return false;
-  case VTypeState_LMUL: {
-    if (!Identifier.consume_front("m"))
-      break;
+  }
+
+  if (State < VTypeState::SeenLmul && Identifier.consume_front("m")) {
+    // Might arrive here if lmul and tail policy unspecified, if so we're
+    // parsing a MaskPolicy not an LMUL.
+    if (Identifier == "a" || Identifier == "u") {
+      MaskAgnostic = (Identifier == "a");
+      State = VTypeState::SeenMaskPolicy;
+      return false;
+    }
+
     Fractional = Identifier.consume_front("f");
     if (Identifier.getAsInteger(10, Lmul))
-      break;
+      return true;
     if (!RISCVVType::isValidLMUL(Lmul, Fractional))
-      break;
+      return true;
 
     if (Fractional) {
       unsigned ELEN = STI->hasFeature(RISCV::FeatureStdExtZve64x) ? 64 : 32;
@@ -2262,30 +2265,32 @@ bool RISCVAsmParser::parseVTypeToken(const AsmToken &Tok, VTypeState &State,
                     Twine(MinLMUL) + " is reserved");
     }
 
-    State = VTypeState_TailPolicy;
+    State = VTypeState::SeenLmul;
     return false;
   }
-  case VTypeState_TailPolicy:
+
+  if (State < VTypeState::SeenTailPolicy && Identifier.starts_with("t")) {
     if (Identifier == "ta")
       TailAgnostic = true;
     else if (Identifier == "tu")
       TailAgnostic = false;
     else
-      break;
-    State = VTypeState_MaskPolicy;
+      return true;
+
+    State = VTypeState::SeenTailPolicy;
     return false;
-  case VTypeState_MaskPolicy:
+  }
+
+  if (State < VTypeState::SeenMaskPolicy && Identifier.starts_with("m")) {
     if (Identifier == "ma")
       MaskAgnostic = true;
     else if (Identifier == "mu")
       MaskAgnostic = false;
     else
-      break;
-    State = VTypeState_Done;
+      return true;
+
+    State = VTypeState::SeenMaskPolicy;
     return false;
-  case VTypeState_Done:
-    // Extra token?
-    break;
   }
 
   return true;
@@ -2294,49 +2299,44 @@ bool RISCVAsmParser::parseVTypeToken(const AsmToken &Tok, VTypeState &State,
 ParseStatus RISCVAsmParser::parseVTypeI(OperandVector &Operands) {
   SMLoc S = getLoc();
 
-  unsigned Sew = 0;
-  unsigned Lmul = 0;
+  // Default values
+  unsigned Sew = 8;
+  unsigned Lmul = 1;
   bool Fractional = false;
   bool TailAgnostic = false;
   bool MaskAgnostic = false;
 
-  VTypeState State = VTypeState_SEW;
-  SMLoc SEWLoc = S;
-
-  if (parseVTypeToken(getTok(), State, Sew, Lmul, Fractional, TailAgnostic,
-                      MaskAgnostic))
-    return ParseStatus::NoMatch;
-
-  getLexer().Lex();
-
-  while (parseOptionalToken(AsmToken::Comma)) {
+  VTypeState State = VTypeState::SeenNothingYet;
+  do {
     if (parseVTypeToken(getTok(), State, Sew, Lmul, Fractional, TailAgnostic,
-                        MaskAgnostic))
+                        MaskAgnostic)) {
+      // The first time, errors return NoMatch rather than Failure
+      if (State == VTypeState::SeenNothingYet)
+        return ParseStatus::NoMatch;
       break;
+    }
 
     getLexer().Lex();
-  }
+  } while (parseOptionalToken(AsmToken::Comma));
 
-  if (getLexer().is(AsmToken::EndOfStatement) && State == VTypeState_Done) {
-    RISCVVType::VLMUL VLMUL = RISCVVType::encodeLMUL(Lmul, Fractional);
-    if (Fractional) {
-      unsigned ELEN = STI->hasFeature(RISCV::FeatureStdExtZve64x) ? 64 : 32;
-      unsigned MaxSEW = ELEN / Lmul;
-      // If MaxSEW < 8, we should have printed warning about reserved LMUL.
-      if (MaxSEW >= 8 && Sew > MaxSEW)
-        Warning(SEWLoc,
-                "use of vtype encodings with SEW > " + Twine(MaxSEW) +
-                    " and LMUL == mf" + Twine(Lmul) +
-                    " may not be compatible with all RVV implementations");
-    }
+  if (!getLexer().is(AsmToken::EndOfStatement) || State == VTypeState::SeenNothingYet)
+    return generateVTypeError(S);
 
-    unsigned VTypeI =
-        RISCVVType::encodeVTYPE(VLMUL, Sew, TailAgnostic, MaskAgnostic);
-    Operands.push_back(RISCVOperand::createVType(VTypeI, S));
-    return ParseStatus::Success;
+  RISCVVType::VLMUL VLMUL = RISCVVType::encodeLMUL(Lmul, Fractional);
+  if (Fractional) {
+    unsigned ELEN = STI->hasFeature(RISCV::FeatureStdExtZve64x) ? 64 : 32;
+    unsigned MaxSEW = ELEN / Lmul;
+    // If MaxSEW < 8, we should have printed warning about reserved LMUL.
+    if (MaxSEW >= 8 && Sew > MaxSEW)
+      Warning(S, "use of vtype encodings with SEW > " + Twine(MaxSEW) +
+                     " and LMUL == mf" + Twine(Lmul) +
+                     " may not be compatible with all RVV implementations");
   }
 
-  return generateVTypeError(S);
+  unsigned VTypeI =
+      RISCVVType::encodeVTYPE(VLMUL, Sew, TailAgnostic, MaskAgnostic);
+  Operands.push_back(RISCVOperand::createVType(VTypeI, S));
+  return ParseStatus::Success;
 }
 
 bool RISCVAsmParser::generateVTypeError(SMLoc ErrorLoc) {
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoV.td b/llvm/lib/Target/RISCV/RISCVInstrInfoV.td
index fe43a2be4aab9..b4ca41461bbe5 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoV.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoV.td
@@ -30,8 +30,8 @@ class VTypeIOp<int VTypeINum> : RISCVOp {
   let MCOperandPredicate = [{
     int64_t Imm;
     if (MCOp.evaluateAsConstantImm(Imm))
-      return isUInt<VTypeINum>(Imm);
-    return MCOp.isBareSymbolRef();
+      return isUInt<}] # VTypeINum # [{>(Imm);
+    return MCOp.Kind == KindTy::VType;
   }];
 }
 
diff --git a/llvm/test/MC/RISCV/rvv/invalid.s b/llvm/test/MC/RISCV/rvv/invalid.s
index 07e7b9db6606c..c89630099776c 100644
--- a/llvm/test/MC/RISCV/rvv/invalid.s
+++ b/llvm/test/MC/RISCV/rvv/invalid.s
@@ -1,12 +1,6 @@
 # RUN: not llvm-mc -triple=riscv64 --mattr=+v --mattr=+f %s 2>&1 \
 # RUN:        | FileCheck %s --check-prefix=CHECK-ERROR
 
-vsetivli a2, 32, e8,m1
-# CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
-
-vsetivli a2, zero, e8,m1
-# CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
-
 vsetivli a2, 5, (1 << 10)
 # CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
 
@@ -22,10 +16,6 @@ vsetvli a2, a0, (1 << 11)
 vsetvli a2, a0, 0x800
 # CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
 
-
-vsetvli a2, a0, e31
-# CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
-
 vsetvli a2, a0, e32,m3
 # CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
 
@@ -59,12 +49,6 @@ vsetvli a2, a0, e8,m1,tx
 vsetvli a2, a0, e8,m1,ta,mx
 # CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
 
-vsetvli a2, a0, e8,m1,ma
-# CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
-
-vsetvli a2, a0, e8,m1,mu
-# CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
-
 vsetvli a2, a0, e8x,m1,tu,mu
 # CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
 
@@ -80,18 +64,12 @@ vsetvli a2, a0, e8,m1,tu,mut
 vsetvli a2, a0, e8,m1,tut,mu
 # CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
 
-vsetvli a2, a0, e8
-# CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
-
-vsetvli a2, a0, e8,m1
-# CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
-
-vsetvli a2, a0, e8,m1,ta
-# CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
-
 vsetvli a2, a0, e8,1,ta,ma
 # CHECK-ERROR: operand must be e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]
 
+vsetvli a2, a0,
+# CHECK-ERROR: unknown operand
+
 vadd.vv v1, v3, v2, v4.t
 # CHECK-ERROR: operand must be v0.t
 
diff --git a/llvm/test/MC/RISCV/rvv/vsetvl.s b/llvm/test/MC/RISCV/rvv/vsetvl.s
index 2741def0eeff2..75c05f9d8b8e9 100644
--- a/llvm/test/MC/RISCV/rvv/vsetvl.s
+++ b/llvm/test/MC/RISCV/rvv/vsetvl.s
@@ -48,7 +48,7 @@ vsetvli a2, a0, 144
 # CHECK-UNKNOWN: 09057657 <unknown>
 
 vsetvli a2, a0, e32, m1, ta, ma
-# CHECK-INST: vsetvli a2, a0, e32,  m1,  ta,  ma
+# CHECK-INST:  vsetvli a2, a0, e32,  m1,  ta,  ma
 # CHECK-ENCODING: [0x57,0x76,0x05,0x0d]
 # CHECK-ERROR: instruction requires the following: 'V' (Vector Extension for Application Processors), 'Zve32x' (Vector Extensions for Embedded Processors){{$}}
 # CHECK-UNKNOWN: 0d057657 <unknown>
@@ -116,6 +116,36 @@ vsetvli a2, a0, e32, m1, tu, mu
 # CHECK-ERROR: instruction requires the following: 'V' (Vector Extension for Application Processors), 'Zve32x' (Vector Extensions for Embedded Processors){{$}}
 # CHECK-UNKNOWN: 01057657 <unknown>
 
+vsetvli a2, a0, 0
+# CHECK-INST: vsetvli a2, a0, e8, m1, tu, mu
+# CHECK-ENCODING: [0x57,0x76,0x05,0x00]
+# CHECK-ERROR: instruction requires the following: 'V' (Vector Extension for Application Processors), 'Zve32x' (Vector Extensions for Embedded Processors){{$}}
+# CHECK-UNKNOWN: 00057657 <unknown>
+
+vsetvli a2, a0, e16
+# CHECK-INST: vsetvli a2, a0, e16, m1, tu, mu
+# CHECK-ENCODING: [0x57,0x76,0x85,0x00]
+# CHECK-ERROR: instruction requires the following: 'V' (Vector Extension for Application Processors), 'Zve32x' (Vector Extensions for Embedded Processors){{$}}
+# CHECK-UNKNOWN: 00857657 <unknown>
+
+vsetvli a2, a0, m2
+# CHECK-INST: vsetvli a2, a0, e8, m2, tu, mu
+# CHECK-ENCODING: [0x57,0x76,0x15,0x00]
+# CHECK-ERROR: instruction requires the following: 'V' (Vector Extension for Application Processors), 'Zve32x' (Vector Extensions for Embedded Processors){{$}}
+# CHECK-UNKNOWN: 00157657 <unknown>
+
+vsetvli a2, a0, ta
+# CHECK-INST: vsetvli a2, a0, e8, m1, ta, mu
+# CHECK-ENCODING: [0x57,0x76,0x05,0x04]
+# CHECK-ERROR: instruction requires the following: 'V' (Vector Extension for Application Processors), 'Zve32x' (Vector Extensions for Embedded Processors){{$}}
+# CHECK-UNKNOWN: 04057657 <unknown>
+
+vsetvli a2, a0, ma
+# CHECK-INST: vsetvli a2, a0, e8, m1, tu, ma
+# CHECK-ENCODING: [0x57,0x76,0x05,0x08]
+# CHECK-ERROR: instruction requires the following: 'V' (Vector Extension for Application Processors), 'Zve32x' (Vector Extensions for Embedded Processors){{$}}
+# CHECK-UNKNOWN: 08057657 <unknown>
+
 vsetvl a2, a0, a1
 # CHECK-INST: vsetvl a2, a0, a1
 # CHECK-ENCODING: [0x57,0x76,0xb5,0x80]
@@ -164,3 +194,33 @@ vsetivli a2, 31, e32, m1, ta, ma
 # CHECK-ENCODING: [0x57,0xf6,0x0f,0xcd]
 # CHECK-ERROR: instruction requires the following: 'V' (Vector Extension for Application Processors), 'Zve32x' (Vector Extensions for Embedded Processors){{$}}
 # CHECK-UNKNOWN: cd0ff657 <unknown>
+
+vsetivli a2, 1, 0
+# CHECK-INST: vsetivli a2, 1, e8, m1, tu, mu
+# CHECK-ENCODING: [0x57,0xf6,0x00,0xc0]
+# CHECK-ERROR: instruction requires the following: 'V' (Vector Extension for Application Processors), 'Zve32x' (Vector Extensions for Embedded Processors){{$}}
+# CHECK-UNKNOWN: c000f657 <unknown>
+
+vsetivli a2, 1, e16
+# CHECK-INST: vsetivli a2, 1, e16, m1, tu, mu
+# CHECK-ENCODING: [0x57,0xf6,0x80,0xc0]
+# CHECK-ERROR: instruction requires the following: 'V' (Vector Extension for Application Processors), 'Zve32x' (Vector Extensions for Embedded Processors){{$}}
+# CHECK-UNKNOWN: c080f657 <unknown>
+
+vsetivli a2, 1, m2
+# CHECK-INST:  vsetivli a2, 1, e8, m2, tu, mu
+# CHECK-ENCODING: [0x57,0xf6,0x10,0xc0]
+# CHECK-ERROR: instruction requires the following: 'V' (Vector Extension for Application Processors), 'Zve32x' (Vector Extensions for Embedded Processors){{$}}
+# CHECK-UNKNOWN: c010f657 <unknown>
+
+vsetivli a2, 1, ta
+# CHECK-INST: vsetivli a2, 1, e8, m1, ta, mu
+# CHECK-ENCODING: [0x57,0xf6,0x00,0xc4]
+# CHECK-ERROR: instruction requires the following: 'V' (Vector Extension for Application Processors), 'Zve32x' (Vector Extensions for Embedded Processors){{$}}
+# CHECK-UNKNOWN: c400f657 <unknown>
+
+vsetivli a2, 1, ma
+# CHECK-INST: vsetivli a2, 1, e8, m1, tu, ma
+# CHECK-ENCODING: [0x57,0xf6,0x00,0xc8]
+# CHECK-ERROR: instruction requires the following: 'V' (Vector Extension for Application Processors), 'Zve32x' (Vector Extensions for Embedded Processors){{$}}
+# CHECK-UNKNOWN: c800f657 <unknown>



More information about the llvm-commits mailing list