diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -125,6 +125,7 @@
   Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
   StringRef CodeModel = getTargetOpts().CodeModel;
   unsigned FLen = ISAInfo->getFLen();
+  unsigned MinVLen = ISAInfo->getMinVLen();
   if (CodeModel == "default")
     CodeModel = "small";
 
@@ -176,6 +177,9 @@
     Builder.defineMacro("__riscv_fsqrt");
   }
 
+  if (MinVLen)
+    Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));
+
   if (ISAInfo->hasExtension("c"))
     Builder.defineMacro("__riscv_compressed");
 
diff --git a/clang/test/CodeGen/RISCV/riscv-metadata.c b/clang/test/CodeGen/RISCV/riscv-metadata.c
--- a/clang/test/CodeGen/RISCV/riscv-metadata.c
+++ b/clang/test/CodeGen/RISCV/riscv-metadata.c
@@ -1,9 +1,9 @@
 // RUN: %clang_cc1 -triple riscv32 -target-abi ilp32 -emit-llvm -o - %s | FileCheck -check-prefix=ILP32 %s
 // RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm -o - %s | FileCheck -check-prefix=ILP32F %s
-// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm -o - %s | FileCheck -check-prefix=ILP32D %s
+// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm -o - %s | FileCheck -check-prefix=ILP32D %s
 // RUN: %clang_cc1 -triple riscv64 -target-abi lp64 -emit-llvm -o - %s | FileCheck -check-prefix=LP64 %s
 // RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm -o - %s | FileCheck -check-prefix=LP64F %s
-// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm -o - %s | FileCheck -check-prefix=LP64D %s
+// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-feature +f -target-abi lp64d -emit-llvm -o - %s | FileCheck -check-prefix=LP64D %s
 
 // ILP32: !{{[0-9]+}} = !{i32 1, !"target-abi", !"ilp32"}
 // ILP32F: !{{[0-9]+}} = !{i32 1, !"target-abi", !"ilp32f"}
diff --git a/clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-ilp32d-abi.c b/clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-ilp32d-abi.c
--- a/clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-ilp32d-abi.c
+++ b/clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-ilp32d-abi.c
@@ -3,7 +3,7 @@
 // RUN:   | FileCheck %s -check-prefixes=CHECK,CHECK-FORCEINT128
 // RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
-// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \
+// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
 
 // This file contains test cases that will have the same output for the ilp32,
diff --git a/clang/test/CodeGen/RISCV/riscv32-ilp32d-abi.c b/clang/test/CodeGen/RISCV/riscv32-ilp32d-abi.c
--- a/clang/test/CodeGen/RISCV/riscv32-ilp32d-abi.c
+++ b/clang/test/CodeGen/RISCV/riscv32-ilp32d-abi.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \
+// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
 
 #include <stdint.h>
diff --git a/clang/test/CodeGen/RISCV/riscv32-ilp32f-ilp32d-abi.c b/clang/test/CodeGen/RISCV/riscv32-ilp32f-ilp32d-abi.c
--- a/clang/test/CodeGen/RISCV/riscv32-ilp32f-ilp32d-abi.c
+++ b/clang/test/CodeGen/RISCV/riscv32-ilp32f-ilp32d-abi.c
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
-// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \
+// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
 
 #include <stdint.h>
diff --git a/clang/test/CodeGen/RISCV/riscv64-lp64-lp64f-lp64d-abi.c b/clang/test/CodeGen/RISCV/riscv64-lp64-lp64f-lp64d-abi.c
--- a/clang/test/CodeGen/RISCV/riscv64-lp64-lp64f-lp64d-abi.c
+++ b/clang/test/CodeGen/RISCV/riscv64-lp64-lp64f-lp64d-abi.c
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -triple riscv64 -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
-// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm %s -o - \
+// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-feature +f -target-abi lp64d -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
 
 // This file contains test cases that will have the same output for the lp64,
diff --git a/clang/test/CodeGen/RISCV/riscv64-lp64d-abi.c b/clang/test/CodeGen/RISCV/riscv64-lp64d-abi.c
--- a/clang/test/CodeGen/RISCV/riscv64-lp64d-abi.c
+++ b/clang/test/CodeGen/RISCV/riscv64-lp64d-abi.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm %s -o - \
+// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-feature +f -target-abi lp64d -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
 
 #include <stdint.h>
diff --git a/clang/test/CodeGen/RISCV/riscv64-lp64f-lp64d-abi.c b/clang/test/CodeGen/RISCV/riscv64-lp64f-lp64d-abi.c
--- a/clang/test/CodeGen/RISCV/riscv64-lp64f-lp64d-abi.c
+++ b/clang/test/CodeGen/RISCV/riscv64-lp64f-lp64d-abi.c
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
-// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm %s -o - \
+// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-feature +f -target-abi lp64d -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
 
 #include <stdint.h>
diff --git a/clang/test/CodeGen/riscv32-ilp32d-abi.cpp b/clang/test/CodeGen/riscv32-ilp32d-abi.cpp
--- a/clang/test/CodeGen/riscv32-ilp32d-abi.cpp
+++ b/clang/test/CodeGen/riscv32-ilp32d-abi.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d \
+// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d \
 // RUN:     -Wno-missing-declarations -emit-llvm %s -o - | FileCheck %s
 
 struct empty_float2 { struct {}; float f; float g; };
diff --git a/clang/test/Driver/riscv-arch.c b/clang/test/Driver/riscv-arch.c
--- a/clang/test/Driver/riscv-arch.c
+++ b/clang/test/Driver/riscv-arch.c
@@ -392,7 +392,7 @@
 
 // RUN: %clang -target riscv32-unknown-elf -march=rv32izbb1p0zbp0p93 -menable-experimental-extensions -### %s \
 // RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-EXPERIMENTAL-ZBB-ZBP-UNDERSCORE %s
-// RV32-EXPERIMENTAL-ZBB-ZBP-UNDERSCORE: error: invalid arch name 'rv32izbb1p0zbp0p93', multi-character extensions must be separated by underscores
+// RV32-EXPERIMENTAL-ZBB-ZBP-UNDERSCORE: error: invalid arch name 'rv32izbb1p0zbp0p93', unsupported version number 0.93 for extension 'zbb1p0zbp'
 
 // RUN: %clang -target riscv32-unknown-elf -march=rv32izba1p0 -menable-experimental-extensions -### %s \
 // RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-EXPERIMENTAL-ZBA %s
@@ -463,3 +463,17 @@
 // RUN: %clang -target riscv32-unknown-elf -march=rv32izvlsseg0p10 -menable-experimental-extensions -### %s -c 2>&1 | \
 // RUN:   FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVLSSEG-GOODVERS %s
 // RV32-EXPERIMENTAL-ZVLSSEG-GOODVERS: "-target-feature" "+experimental-zvlsseg"
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32izvl32b0p10 -### %s -c 2>&1 | \
+// RUN:   FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVL-NOFLAG %s
+// RV32-EXPERIMENTAL-ZVL-NOFLAG: error: invalid arch name 'rv32izvl32b0p10'
+// RV32-EXPERIMENTAL-ZVL-NOFLAG: requires '-menable-experimental-extensions'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32izvl32b0p1 -menable-experimental-extensions -### %s -c 2>&1 | \
+// RUN:   FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVL-BADVERS %s
+// RV32-EXPERIMENTAL-ZVL-BADVERS: error: invalid arch name 'rv32izvl32b0p1'
+// RV32-EXPERIMENTAL-ZVL-BADVERS: unsupported version number 0.1 for experimental extension
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32izvl32b0p10 -menable-experimental-extensions -### %s -c 2>&1 | \
+// RUN:   FileCheck -check-prefix=RV32-EXPERIMENTAL-ZVL-GOODVERS %s
+// RV32-EXPERIMENTAL-ZVL-GOODVERS: "-target-feature" "+experimental-zvl32b"
diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c
--- a/clang/test/Preprocessor/riscv-target-features.c
+++ b/clang/test/Preprocessor/riscv-target-features.c
@@ -223,3 +223,8 @@
 // RUN: -march=rv64izfh0p1 -x c -E -dM %s \
 // RUN: -o - | FileCheck --check-prefix=CHECK-ZFH-EXT %s
 // CHECK-ZFH-EXT: __riscv_zfh 1000
+
+// RUN: %clang -target riscv32-unknown-linux-gnu -menable-experimental-extensions \
+// RUN: -march=rv64iv0p10 -x c -E -dM %s -o - \
+// RUN: | FileCheck --check-prefix=CHECK-V-MINVLEN %s
+// CHECK-V-MINVLEN: __riscv_v_min_vlen 128
diff --git a/llvm/include/llvm/Support/RISCVISAInfo.h b/llvm/include/llvm/Support/RISCVISAInfo.h
--- a/llvm/include/llvm/Support/RISCVISAInfo.h
+++ b/llvm/include/llvm/Support/RISCVISAInfo.h
@@ -61,6 +61,7 @@
 
   unsigned getXLen() const { return XLen; };
   unsigned getFLen() const { return FLen; };
+  unsigned getMinVLen() const { return MinVLen; }
 
   bool hasExtension(StringRef Ext) const;
   std::string toString() const;
@@ -71,17 +72,22 @@
                                    unsigned MinorVersion);
 
 private:
-  RISCVISAInfo(unsigned XLen) : XLen(XLen), FLen(0) {}
+  RISCVISAInfo(unsigned XLen) : XLen(XLen), FLen(0), MinVLen(0) {}
 
   unsigned XLen;
   unsigned FLen;
+  unsigned MinVLen;
 
   OrderedExtensionMap Exts;
 
   void addExtension(StringRef ExtName, unsigned MajorVersion,
                     unsigned MinorVersion);
 
+  Error checkDependency();
+
+  void updateImplication();
   void updateFLen();
+  void updateMinVLen();
 };
 
 } // namespace llvm
diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp
--- a/llvm/lib/Support/RISCVISAInfo.cpp
+++ b/llvm/lib/Support/RISCVISAInfo.cpp
@@ -10,6 +10,7 @@
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/Error.h"
@@ -18,6 +19,7 @@
 #include <array>
 #include <string>
 #include <vector>
+#include <iostream>
 
 using namespace llvm;
 
@@ -63,6 +65,18 @@
 
     {"zvamo", RISCVExtensionVersion{0, 10}},
     {"zvlsseg", RISCVExtensionVersion{0, 10}},
+    {"zvl32b", RISCVExtensionVersion{0, 10}},
+    {"zvl64b", RISCVExtensionVersion{0, 10}},
+    {"zvl128b", RISCVExtensionVersion{0, 10}},
+    {"zvl256b", RISCVExtensionVersion{0, 10}},
+    {"zvl512b", RISCVExtensionVersion{0, 10}},
+    {"zvl1024b", RISCVExtensionVersion{0, 10}},
+    {"zvl2048b", RISCVExtensionVersion{0, 10}},
+    {"zvl4096b", RISCVExtensionVersion{0, 10}},
+    {"zvl8192b", RISCVExtensionVersion{0, 10}},
+    {"zvl16384b", RISCVExtensionVersion{0, 10}},
+    {"zvl32768b", RISCVExtensionVersion{0, 10}},
+    {"zvl65536b", RISCVExtensionVersion{0, 10}},
 
     {"zfh", RISCVExtensionVersion{0, 1}},
 };
@@ -411,7 +425,6 @@
   assert(XLen == 32 || XLen == 64);
   std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
 
-  bool HasE = false;
   for (auto &Feature : Features) {
     StringRef ExtName = Feature;
     bool Experimental = false;
@@ -430,28 +443,19 @@
     if (ExtensionInfoIterator == ExtensionInfos.end())
       continue;
 
-    if (Add) {
-      if (ExtName == "e") {
-        if (XLen != 32)
-          return createStringError(
-              errc::invalid_argument,
-              "standard user-level extension 'e' requires 'rv32'");
-        HasE = true;
-      }
-
+    if (Add)
       ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major,
                             ExtensionInfoIterator->Version.Minor);
-    } else
-      ISAInfo->Exts.erase(ExtName.str());
-  }
-  if (!HasE) {
-    if (auto Version = findDefaultVersion("i"))
-      ISAInfo->addExtension("i", Version->Major, Version->Minor);
     else
-      llvm_unreachable("Default extension version for 'i' not found?");
+      ISAInfo->Exts.erase(ExtName.str());
   }
 
   ISAInfo->updateFLen();
+  ISAInfo->updateImplication();
+  ISAInfo->updateMinVLen();
+
+  if (Error Result = ISAInfo->checkDependency())
+    return std::move(Result);
 
   return std::move(ISAInfo);
 }
@@ -478,7 +482,6 @@
   // The canonical order specified in ISA manual.
   // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
   StringRef StdExts = AllStdExts;
-  bool HasF = false, HasD = false;
   char Baseline = Arch[4];
 
   // First letter should be 'e', 'i' or 'g'.
@@ -499,8 +502,6 @@
   case 'g':
     // g = imafd
     StdExts = StdExts.drop_front(4);
-    HasF = true;
-    HasD = true;
     break;
   }
 
@@ -518,6 +519,8 @@
     Exts = Exts.substr(0, Pos);
   }
 
+  dbgs() << OtherExts << "\n";
+
   unsigned Major, Minor, ConsumeLength;
   if (auto E = getExtensionVersion(std::string(1, Baseline), Exts, Major, Minor,
                                    ConsumeLength, EnableExperimentalExtension,
@@ -581,34 +584,14 @@
 
     // The order is OK, then push it into features.
     // TODO: Use version number when setting target features
-    switch (C) {
-    default:
-      // Currently LLVM supports only "mafdcbv".
+    // Currently LLVM supports only "mafdcbv".
+    StringRef SupportedStandardExtension = "mafdcbv";
+    if (SupportedStandardExtension.find(C) == StringRef::npos)
       return createStringError(errc::invalid_argument,
                                "unsupported standard user-level extension '%c'",
                                C);
-    case 'm':
-      ISAInfo->addExtension("m", Major, Minor);
-      break;
-    case 'a':
-      ISAInfo->addExtension("a", Major, Minor);
-      break;
-    case 'f':
-      ISAInfo->addExtension("f", Major, Minor);
-      HasF = true;
-      break;
-    case 'd':
-      ISAInfo->addExtension("d", Major, Minor);
-      HasD = true;
-      break;
-    case 'c':
-      ISAInfo->addExtension("c", Major, Minor);
-      break;
-    case 'v':
-      ISAInfo->addExtension("v", Major, Minor);
-      ISAInfo->addExtension("zvlsseg", Major, Minor);
-      break;
-    }
+    ISAInfo->addExtension(std::string(1, C), Major, Minor);
+
     // Consume full extension name and version, including any optional '_'
     // between this extension and the next
     ++I;
@@ -616,21 +599,6 @@
     if (*I == '_')
       ++I;
   }
-  // Dependency check.
-  // It's illegal to specify the 'd' (double-precision floating point)
-  // extension without also specifying the 'f' (single precision
-  // floating-point) extension.
-  // TODO: This has been removed in later specs, which specify that D implies F
-  if (HasD && !HasF)
-    return createStringError(errc::invalid_argument,
-                             "d requires f extension to also be specified");
-
-  // Additional dependency checks.
-  // TODO: The 'q' extension requires rv64.
-  // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
-
-  if (OtherExts.empty())
-    return std::move(ISAInfo);
 
   // Handle other types of extensions other than the standard
   // general purpose and standard user-level extensions.
@@ -651,52 +619,53 @@
   std::array<StringRef, 4> Prefix{"z", "x", "s", "sx"};
   auto I = Prefix.begin();
   auto E = Prefix.end();
+  if (Split.size() > 1 || Split[0] != "") {
+    for (StringRef Ext : Split) {
+      if (Ext.empty())
+        return createStringError(errc::invalid_argument,
+                                "extension name missing after separator '_'");
+
+      StringRef Type = getExtensionType(Ext);
+      StringRef Desc = getExtensionTypeDesc(Ext);
+      auto Pos = findFirstNonVersionCharacter(Ext) + 1;
+      StringRef Name(Ext.substr(0, Pos));
+      StringRef Vers(Ext.substr(Pos));
+
+      if (Type.empty())
+        return createStringError(errc::invalid_argument,
+                                "invalid extension prefix '" + Ext + "'");
+
+      // Check ISA extensions are specified in the canonical order.
+      while (I != E && *I != Type)
+        ++I;
+
+      if (I == E)
+        return createStringError(errc::invalid_argument,
+                                "%s not given in canonical order '%s'",
+                                Desc.str().c_str(), Ext.str().c_str());
+
+      if (Name.size() == Type.size()) {
+        return createStringError(errc::invalid_argument,
+                                "%s name missing after '%s'", Desc.str().c_str(),
+                                Type.str().c_str());
+      }
 
-  for (StringRef Ext : Split) {
-    if (Ext.empty())
-      return createStringError(errc::invalid_argument,
-                               "extension name missing after separator '_'");
-
-    StringRef Type = getExtensionType(Ext);
-    StringRef Desc = getExtensionTypeDesc(Ext);
-    size_t Pos = findFirstNonVersionCharacter(Ext) + 1;
-    StringRef Name(Ext.substr(0, Pos));
-    StringRef Vers(Ext.substr(Pos));
-
-    if (Type.empty())
-      return createStringError(errc::invalid_argument,
-                               "invalid extension prefix '" + Ext + "'");
-
-    // Check ISA extensions are specified in the canonical order.
-    while (I != E && *I != Type)
-      ++I;
-
-    if (I == E)
-      return createStringError(errc::invalid_argument,
-                               "%s not given in canonical order '%s'",
-                               Desc.str().c_str(), Ext.str().c_str());
-
-    if (Name.size() == Type.size()) {
-      return createStringError(errc::invalid_argument,
-                               "%s name missing after '%s'", Desc.str().c_str(),
-                               Type.str().c_str());
+      unsigned Major, Minor, ConsumeLength;
+      if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
+                                      EnableExperimentalExtension,
+                                      ExperimentalExtensionVersionCheck))
+        return std::move(E);
+
+      // Check if duplicated extension.
+      if (llvm::is_contained(AllExts, Name))
+        return createStringError(errc::invalid_argument, "duplicated %s '%s'",
+                                Desc.str().c_str(), Name.str().c_str());
+
+      ISAInfo->addExtension(Name, Major, Minor);
+      // Extension format is correct, keep parsing the extensions.
+      // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
+      AllExts.push_back(Name);
     }
-
-    unsigned Major, Minor, ConsumeLength;
-    if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
-                                     EnableExperimentalExtension,
-                                     ExperimentalExtensionVersionCheck))
-      return std::move(E);
-
-    // Check if duplicated extension.
-    if (llvm::is_contained(AllExts, Name))
-      return createStringError(errc::invalid_argument, "duplicated %s '%s'",
-                               Desc.str().c_str(), Name.str().c_str());
-
-    ISAInfo->addExtension(Name, Major, Minor);
-    // Extension format is correct, keep parsing the extensions.
-    // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
-    AllExts.push_back(Name);
   }
 
   for (auto Ext : AllExts) {
@@ -707,11 +676,92 @@
     }
   }
 
+  ISAInfo->updateImplication();
   ISAInfo->updateFLen();
+  ISAInfo->updateMinVLen();
+
+  if (Error Result = ISAInfo->checkDependency())
+    return std::move(Result);
 
   return std::move(ISAInfo);
 }
 
+Error RISCVISAInfo::checkDependency() {
+  bool IsRv32 = XLen == 32;
+  bool HasE = Exts.count("e") == 1;
+  bool HasD = Exts.count("d") == 1;
+  bool HasF = Exts.count("f") == 1;
+
+  if (HasE && !IsRv32)
+    return createStringError(
+      errc::invalid_argument,
+      "standard user-level extension 'e' requires 'rv32'");
+
+  // It's illegal to specify the 'd' (double-precision floating point)
+  // extension without also specifying the 'f' (single precision
+  // floating-point) extension.
+  // TODO: This has been removed in later specs, which specify that D implies F
+  if (HasD && !HasF)
+    return createStringError(
+        errc::invalid_argument,
+        "d requires f extension to also be specified");
+
+  // Additional dependency checks.
+  // TODO: The 'q' extension requires rv64.
+  // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
+
+  return Error::success();
+}
+
+void RISCVISAInfo::updateImplication() {
+  const StringMap<std::vector<StringRef>> Implications = {
+    {"v", {"zvlsseg", "zvl128b"}},
+
+    {"zvl64b", {"zvl32b"}},
+    {"zvl128b", {"zvl64b"}},
+    {"zvl256b", {"zvl128b"}},
+    {"zvl512b", {"zvl256b"}},
+    {"zvl1024b", {"zvl512b"}},
+    {"zvl2048b", {"zvl1024b"}},
+    {"zvl4096b", {"zvl2048b"}},
+    {"zvl8192b", {"zvl4096b"}},
+    {"zvl16384b", {"zvl8192b"}},
+    {"zvl32768b", {"zvl16384b"}},
+    {"zvl65536b", {"zvl32768b"}},
+  };
+  bool HasE = Exts.count("e") == 1;
+  bool HasI = Exts.count("i") == 1;
+
+  // If not in e extension and i extension does not exist, i extension is
+  // implied
+  if (!HasE && !HasI) {
+    auto Version = findDefaultVersion("i");
+    addExtension("i", Version->Major, Version->Minor);
+  }
+
+  // This loop may execute over 1 iteration since implication can be layered
+  // Exits loop if no more implication is applied
+  SmallSetVector<StringRef, 16> WorkList;
+  for (auto &Ext : Exts)
+    WorkList.insert(Ext.first);
+
+  while (!WorkList.empty()) {
+    auto ExtName = WorkList.pop_back_val();
+    auto Implication = Implications.find(ExtName);
+    if (Implication != Implications.end()) {
+      for (auto ImpliedExtName : Implication->second) {
+        if (WorkList.count(ImpliedExtName))
+          continue;
+        if (Exts.count(ImpliedExtName.str()))
+          continue;
+        auto Version = findDefaultVersion(ImpliedExtName);
+        addExtension(ImpliedExtName, Version->Major, Version->Minor);
+        WorkList.insert(ImpliedExtName);
+      }
+    }
+  }
+}
+
 void RISCVISAInfo::updateFLen() {
   FLen = 0;
   // TODO: Handle q extension.
@@ -721,6 +771,19 @@
     FLen = 32;
 }
 
+void RISCVISAInfo::updateMinVLen() {
+  for (auto &Ext : Exts) {
+    StringRef ExtName = Ext.first;
+    bool IsZvlExt = ExtName.consume_front("zvl");
+    if (IsZvlExt) {
+      ExtName.consume_back("b");
+      unsigned ZvlLen;
+      ExtName.getAsInteger(10, ZvlLen);
+      MinVLen = std::max(MinVLen, ZvlLen);
+    }
+  }
+}
+
 std::string RISCVISAInfo::toString() const {
   std::string Buffer;
   raw_string_ostream Arch(Buffer);
diff --git a/llvm/lib/Target/RISCV/RISCV.td b/llvm/lib/Target/RISCV/RISCV.td
--- a/llvm/lib/Target/RISCV/RISCV.td
+++ b/llvm/lib/Target/RISCV/RISCV.td
@@ -142,9 +142,47 @@
                   AssemblerPredicate<(all_of(not FeatureNoRVCHints)),
                                       "RVC Hint Instructions">;
 
+def FeatureStdExtZvl32b : SubtargetFeature<"experimental-zvl32b", "ZvlLen", "ExtZvl::Zvl32b",
+                       "'Zvl' (Minimum Vector Length) 32">;
+def FeatureStdExtZvl64b : SubtargetFeature<"experimental-zvl64b", "ZvlLen", "ExtZvl::Zvl64b",
+                       "'Zvl' (Minimum Vector Length) 64",
+                       [FeatureStdExtZvl32b]>;
+def FeatureStdExtZvl128b : SubtargetFeature<"experimental-zvl128b", "ZvlLen", "ExtZvl::Zvl128b",
+                       "'Zvl' (Minimum Vector Length) 128",
+                       [FeatureStdExtZvl64b]>;
+def FeatureStdExtZvl256b : SubtargetFeature<"experimental-zvl256b", "ZvlLen", "ExtZvl::Zvl256b",
+                       "'Zvl' (Minimum Vector Length) 256",
+                       [FeatureStdExtZvl128b]>;
+def FeatureStdExtZvl512b : SubtargetFeature<"experimental-zvl512b", "ZvlLen", "ExtZvl::Zvl512b",
+                       "'Zvl' (Minimum Vector Length) 512",
+                       [FeatureStdExtZvl256b]>;
+def FeatureStdExtZvl1024b : SubtargetFeature<"experimental-zvl1024b", "ZvlLen", "ExtZvl::Zvl1024b",
+                       "'Zvl' (Minimum Vector Length) 1024",
+                       [FeatureStdExtZvl512b]>;
+def FeatureStdExtZvl2048b : SubtargetFeature<"experimental-zvl2048b", "ZvlLen", "ExtZvl::Zvl2048b",
+                       "'Zvl' (Minimum Vector Length) 2048",
+                       [FeatureStdExtZvl1024b]>;
+def FeatureStdExtZvl4096b : SubtargetFeature<"experimental-zvl4096b", "ZvlLen", "ExtZvl::Zvl4096b",
+                       "'Zvl' (Minimum Vector Length) 4096",
+                       [FeatureStdExtZvl2048b]>;
+def FeatureStdExtZvl8192b : SubtargetFeature<"experimental-zvl8192b", "ZvlLen", "ExtZvl::Zvl8192b",
+                       "'Zvl' (Minimum Vector Length) 8192",
+                       [FeatureStdExtZvl4096b]>;
+def FeatureStdExtZvl16384b : SubtargetFeature<"experimental-zvl16384b", "ZvlLen", "ExtZvl::Zvl16384b",
+                       "'Zvl' (Minimum Vector Length) 16384",
+                       [FeatureStdExtZvl8192b]>;
+def FeatureStdExtZvl32768b : SubtargetFeature<"experimental-zvl32768b", "ZvlLen", "ExtZvl::Zvl32768b",
+                       "'Zvl' (Minimum Vector Length) 32768",
+                       [FeatureStdExtZvl16384b]>;
+def FeatureStdExtZvl65536b : SubtargetFeature<"experimental-zvl65536b", "ZvlLen", "ExtZvl::Zvl65536b",
+                       "'Zvl' (Minimum Vector Length) 65536",
+                       [FeatureStdExtZvl32768b]>;
+def HasStdExtZvl : Predicate<"Subtarget->hasStdExtZvl()">;
+
 def FeatureStdExtV
     : SubtargetFeature<"experimental-v", "HasStdExtV", "true",
-                       "'V' (Vector Instructions)">;
+                       "'V' (Vector Instructions)",
+                       [FeatureStdExtZvl128b]>;
 def HasStdExtV : Predicate<"Subtarget->hasStdExtV()">,
                            AssemblerPredicate<(all_of FeatureStdExtV),
                            "'V' (Vector Instructions)">;
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.h
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h
@@ -33,6 +33,22 @@
 class StringRef;
 
 class RISCVSubtarget : public RISCVGenSubtargetInfo {
+  enum ExtZvl : unsigned {
+    NotSet = 0,
+    Zvl32b = 32,
+    Zvl64b = 64,
+    Zvl128b = 128,
+    Zvl256b = 256,
+    Zvl512b = 512,
+    Zvl1024b = 1024,
+    Zvl2048b = 2048,
+    Zvl4096b = 4096,
+    Zvl8192b = 8192,
+    Zvl16384b = 16384,
+    Zvl32768b = 32768,
+    Zvl65536b = 65536
+  };
+
   virtual void anchor();
   bool HasStdExtM = false;
   bool HasStdExtA = false;
@@ -59,6 +75,7 @@
   bool EnableRVCHintInstrs = true;
   bool EnableSaveRestore = false;
   unsigned XLen = 32;
+  ExtZvl ZvlLen = ExtZvl::NotSet;
   MVT XLenVT = MVT::i32;
   uint8_t MaxInterleaveFactor = 2;
   RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown;
@@ -117,6 +134,7 @@
   bool hasStdExtZbt() const { return HasStdExtZbt; }
   bool hasStdExtV() const { return HasStdExtV; }
   bool hasStdExtZvlsseg() const { return HasStdExtZvlsseg; }
+  bool hasStdExtZvl() const { return ZvlLen != ExtZvl::NotSet; }
   bool hasStdExtZvamo() const { return HasStdExtZvamo; }
   bool hasStdExtZfh() const { return HasStdExtZfh; }
   bool is64Bit() const { return HasRV64; }
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -136,6 +136,9 @@
   assert((RVVVectorBitsMax >= RVVVectorBitsMin || RVVVectorBitsMax == 0) &&
          "Minimum V extension vector length should not be larger than its "
          "maximum!");
+  if (RVVVectorBitsMin != 0 && RVVVectorBitsMin < ZvlLen)
+    report_fatal_error(Twine("riscv-v-vector-bits-min specified is lower than "
+                             "the Zvl*b limitation"));
   unsigned Min = RVVVectorBitsMin;
   if (RVVVectorBitsMax != 0)
     Min = std::min(RVVVectorBitsMin, RVVVectorBitsMax);
diff --git a/llvm/test/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll
--- a/llvm/test/CodeGen/RISCV/attributes.ll
+++ b/llvm/test/CodeGen/RISCV/attributes.ll
@@ -42,7 +42,7 @@
 ; RV32F: .attribute 5, "rv32i2p0_f2p0"
 ; RV32D: .attribute 5, "rv32i2p0_f2p0_d2p0"
 ; RV32C: .attribute 5, "rv32i2p0_c2p0"
-; RV32V: .attribute 5, "rv32i2p0_v0p10_zvamo0p10_zvlsseg0p10"
+; RV32V: .attribute 5, "rv32i2p0_v0p10_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
 ; RV32ZFH: .attribute 5, "rv32i2p0_f2p0_zfh0p1"
 ; RV32ZBA: .attribute 5, "rv32i2p0_zba1p0"
 ; RV32ZBB: .attribute 5, "rv32i2p0_zbb1p0"
@@ -54,7 +54,7 @@
 ; RV32ZBR: .attribute 5, "rv32i2p0_zbr0p93"
 ; RV32ZBS: .attribute 5, "rv32i2p0_zbs1p0"
 ; RV32ZBT: .attribute 5, "rv32i2p0_zbt0p93"
-; RV32COMBINED: .attribute 5, "rv32i2p0_f2p0_v0p10_zfh0p1_zbb1p0_zvamo0p10_zvlsseg0p10"
+; RV32COMBINED: .attribute 5, "rv32i2p0_f2p0_v0p10_zfh0p1_zbb1p0_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
 
 ; RV64M: .attribute 5, "rv64i2p0_m2p0"
 ; RV64A: .attribute 5, "rv64i2p0_a2p0"
@@ -72,8 +72,8 @@
 ; RV64ZBR: .attribute 5, "rv64i2p0_zbr0p93"
 ; RV64ZBS: .attribute 5, "rv64i2p0_zbs1p0"
 ; RV64ZBT: .attribute 5, "rv64i2p0_zbt0p93"
-; RV64V: .attribute 5, "rv64i2p0_v0p10_zvamo0p10_zvlsseg0p10"
-; RV64COMBINED: .attribute 5, "rv64i2p0_f2p0_v0p10_zfh0p1_zbb1p0_zvamo0p10_zvlsseg0p10"
+; RV64V: .attribute 5, "rv64i2p0_v0p10_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
+; RV64COMBINED: .attribute 5, "rv64i2p0_f2p0_v0p10_zfh0p1_zbb1p0_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
 
 
 define i32 @addi(i32 %a) {
diff --git a/llvm/test/MC/RISCV/attribute-arch.s b/llvm/test/MC/RISCV/attribute-arch.s
--- a/llvm/test/MC/RISCV/attribute-arch.s
+++ b/llvm/test/MC/RISCV/attribute-arch.s
@@ -34,7 +34,7 @@
 # CHECK: attribute      5, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
 
 .attribute arch, "rv32iv"
-# CHECK: attribute      5, "rv32i2p0_v0p10_zvlsseg0p10"
+# CHECK: attribute      5, "rv32i2p0_v0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
 
 .attribute arch, "rv32izba"
 # CHECK: attribute      5, "rv32i2p0_zba1p0"
@@ -70,7 +70,43 @@
 # CHECK: attribute      5, "rv32i2p0_f2p0_zfh0p1"
 
 .attribute arch, "rv32ivzvamo_zvlsseg"
-# CHECK: attribute      5, "rv32i2p0_v0p10_zvamo0p10_zvlsseg0p10"
+# CHECK: attribute      5, "rv32i2p0_v0p10_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
 
 .attribute arch, "rv32iv_zvamo0p10_zvlsseg"
-# CHECK: attribute      5, "rv32i2p0_v0p10_zvamo0p10_zvlsseg0p10"
+# CHECK: attribute      5, "rv32i2p0_v0p10_zvamo0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
+
+.attribute arch, "rv32ifdv_zvl32b"
+# CHECK: attribute      5, "rv32i2p0_f2p0_d2p0_v0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
+
+.attribute arch, "rv32ifdv_zvl64b"
+# CHECK: attribute      5, "rv32i2p0_f2p0_d2p0_v0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
+
+.attribute arch, "rv32ifdv_zvl128b"
+# CHECK: attribute      5, "rv32i2p0_f2p0_d2p0_v0p10_zvl128b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
+
+.attribute arch, "rv32ifdv_zvl256b"
+# CHECK: attribute      5, "rv32i2p0_f2p0_d2p0_v0p10_zvl128b0p10_zvl256b0p10_zvl32b0p10_zvl64b0p10_zvlsseg0p10"
+
+.attribute arch, "rv32ifdv_zvl512b"
+# CHECK: attribute      5, "rv32i2p0_f2p0_d2p0_v0p10_zvl128b0p10_zvl256b0p10_zvl32b0p10_zvl512b0p10_zvl64b0p10_zvlsseg0p10"
+
+.attribute arch, "rv32ifdv_zvl1024b"
+# CHECK: attribute      5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl256b0p10_zvl32b0p10_zvl512b0p10_zvl64b0p10_zvlsseg0p10"
+
+.attribute arch, "rv32ifdv_zvl2048b"
+# CHECK: attribute      5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl2048b0p10_zvl256b0p10_zvl32b0p10_zvl512b0p10_zvl64b0p10_zvlsseg0p10"
+
+.attribute arch, "rv32ifdv_zvl4096b"
+# CHECK: attribute      5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl2048b0p10_zvl256b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvlsseg0p10"
+
+.attribute arch, "rv32ifdv_zvl8192b"
+# CHECK: attribute      5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl2048b0p10_zvl256b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvl8192b0p10_zvlsseg0p10"
+
+.attribute arch, "rv32ifdv_zvl16384b"
+# CHECK: attribute      5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl16384b0p10_zvl2048b0p10_zvl256b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvl8192b0p10_zvlsseg0p10"
+
+.attribute arch, "rv32ifdv_zvl32768b"
+# CHECK: attribute      5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl16384b0p10_zvl2048b0p10_zvl256b0p10_zvl32768b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvl8192b0p10_zvlsseg0p10"
+
+.attribute arch, "rv32ifdv_zvl65536b"
+# CHECK: attribute      5, "rv32i2p0_f2p0_d2p0_v0p10_zvl1024b0p10_zvl128b0p10_zvl16384b0p10_zvl2048b0p10_zvl256b0p10_zvl32768b0p10_zvl32b0p10_zvl4096b0p10_zvl512b0p10_zvl64b0p10_zvl65536b0p10_zvl8192b0p10_zvlsseg0p10"