[RISCV] More validations on the input value of -march=
authorAna Pazos <apazos@codeaurora.org>
Wed, 25 Apr 2018 22:42:38 +0000 (22:42 +0000)
committerAna Pazos <apazos@codeaurora.org>
Wed, 25 Apr 2018 22:42:38 +0000 (22:42 +0000)
Supporting additional rules for parsing ISA string.

- RISC-V ISA strings must be lowercase.
E.g.: rv32IMC is not supported, rv32imc is correct.

- Multi-letter extensions are to be separated by a single
underscore '_'. The extension prefix counts as a letter.
This means extensions that start with 's', 'sx' and 'sx'
are all multi-letter.
E.g.:
xasb is a single non-standard extension named 'xasb'
xa_sb are two extensions, the non-standard user level extension
'xa', and the supervisor level extension 'sb'.

- Standard user-level extensions are specified following
a canonical order, according to Table 22.1 in
RISC-V User-Level ISA V2.2.

- Non-standard user-level 'x' extensions,
standard supervisor-level 's' extensions and
non-standard supervisor-level 'sx' extensions
are also specified following a canonical order according
to Table 22.1 in RISC-V User-Level ISA V2.2:
'x' extensions, follwed by 's' extensions and then 'sx' extensions.

- Extensions might have a version number.
Underscores may be used to separate ISA subset components to
improve readability and to provide disambiguation.
E.g.: rv32i2_m3_a1_f2_d2

- Version numbers are divided into major and minor numbers,
separated by a 'p'. If the minor version is 0, then 'p0' can
be omitted.

- Additional checks for dependent extensions and invalid
extensions combinations.
E.g.:
'e' requires rv32
'e' can't be combined with 'f' nor 'd'
'q' requires rv64

- TODO items have also been marked with comments in the code.

Reviewers: asb, kito-cheng

Reviewed By: asb

Subscribers: edward-jones, mgrang, zzheng, rbar, johnrusso, simoncook, jordy.potman.lists, sabuasal, niosHD, shiva0217, cfe-commits

Differential Revision: https://reviews.llvm.org/D45284

llvm-svn: 330880

clang/include/clang/Basic/DiagnosticDriverKinds.td
clang/lib/Driver/ToolChains/Arch/RISCV.cpp
clang/test/Driver/riscv-arch.c

index a8da85f..988a833 100644 (file)
@@ -24,6 +24,10 @@ def err_drv_unknown_stdin_type_clang_cl : Error<
 def err_drv_unknown_language : Error<"language not recognized: '%0'">;
 def err_drv_invalid_arch_name : Error<
   "invalid arch name '%0'">;
+def err_drv_invalid_riscv_arch_name : Error<
+  "invalid arch name '%0', %1">;
+def err_drv_invalid_riscv_ext_arch_name : Error<
+  "invalid arch name '%0', %1 '%2'">;
 def err_drv_cuda_bad_gpu_arch : Error<"Unsupported CUDA gpu architecture: %0">;
 def err_drv_no_cuda_installation : Error<
   "cannot find CUDA installation.  Provide its path via --cuda-path, or pass "
index 9bcc262..18f5982 100644 (file)
@@ -20,32 +20,232 @@ using namespace clang::driver::tools;
 using namespace clang;
 using namespace llvm::opt;
 
+static StringRef getExtensionTypeDesc(StringRef Ext) {
+  if (Ext.startswith("sx"))
+    return "non-standard supervisor-level extension";
+  if (Ext.startswith("s"))
+    return "standard supervisor-level extension";
+  if (Ext.startswith("x"))
+    return "non-standard user-level extension";
+  return StringRef();
+}
+
+static StringRef getExtensionType(StringRef Ext) {
+  if (Ext.startswith("sx"))
+    return "sx";
+  if (Ext.startswith("s"))
+    return "s";
+  if (Ext.startswith("x"))
+    return "x";
+  return StringRef();
+}
+
+static bool isSupportedExtension(StringRef Ext) {
+  // LLVM does not support "sx", "s" nor "x" extensions.
+  return false;
+}
+
+// Extensions may have a version number, and may be separated by
+// an underscore '_' e.g.: rv32i2_m2.
+// Version number is divided into major and minor version numbers,
+// separated by a 'p'. If the minor version is 0 then 'p0' can be
+// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
+static bool getExtensionVersion(const Driver &D, StringRef MArch,
+                                StringRef Ext, StringRef In,
+                                std::string &Major, std::string &Minor) {
+  auto I = In.begin();
+  auto E = In.end();
+
+  while (I != E && isdigit(*I))
+    Major.append(1, *I++);
+
+  if (Major.empty())
+    return true;
+
+  if (I != E && *I == 'p') {
+    ++I;
+
+    while (I != E && isdigit(*I))
+      Minor.append(1, *I++);
+
+    // Expected 'p' to be followed by minor version number.
+    if (Minor.empty()) {
+      std::string Error =
+        "minor version number missing after 'p' for extension";
+      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
+        << MArch << Error << Ext;
+      return false;
+    }
+  }
+
+  // TODO: Handle extensions with version number.
+  std::string Error = "unsupported version number " + Major;
+  if (!Minor.empty())
+    Error += "." + Minor;
+  Error += " for extension";
+  D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << Ext;
+
+  return false;
+}
+
+// Handle other types of extensions other than the standard
+// general purpose and standard user-level extensions.
+// Parse the ISA string containing non-standard user-level
+// extensions, standard supervisor-level extensions and
+// non-standard supervisor-level extensions.
+// These extensions start with 'x', 's', 'sx' prefixes, follow a
+// canonical order, might have a version number (major, minor)
+// and are separated by a single underscore '_'.
+// Set the hardware features for the extensions that are supported.
+static void getExtensionFeatures(const Driver &D,
+                                 const ArgList &Args,
+                                 std::vector<StringRef> &Features,
+                                 StringRef &MArch, StringRef &Exts) {
+  if (Exts.empty())
+    return;
+
+  // Multi-letter extensions are seperated by a single underscore
+  // as described in RISC-V User-Level ISA V2.2.
+  SmallVector<StringRef, 8> Split;
+  Exts.split(Split, StringRef("_"));
+
+  SmallVector<StringRef, 3> Prefix;
+  Prefix.push_back("x");
+  Prefix.push_back("s");
+  Prefix.push_back("sx");
+  auto I = Prefix.begin();
+  auto E = Prefix.end();
+
+  SmallVector<StringRef, 8> AllExts;
+
+  for (StringRef Ext : Split) {
+
+    if (Ext.empty()) {
+      D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
+        << "extension name missing after separator '_'";
+      return;
+    }
+
+    StringRef Type = getExtensionType(Ext);
+    StringRef Name(Ext.substr(Type.size()));
+    StringRef Desc = getExtensionTypeDesc(Ext);
+
+    if (Type.empty()) {
+      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
+        << MArch << "invalid extension prefix" << Ext;
+      return;
+    }
+
+    // Check ISA extensions are specified in the canonical order.
+    while (I != E && *I != Type)
+      ++I;
+
+    if (I == E) {
+      std::string Error = Desc;
+      Error += " not given in canonical order";
+      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
+        << MArch <<  Error << Ext;
+      return;
+    }
+
+    // The order is OK, do not advance I to the next prefix
+    // to allow repeated extension type, e.g.: rv32ixabc_xdef.
+
+    if (Name.empty()) {
+      std::string Error = Desc;
+      Error += " name missing after";
+      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
+        << MArch << Error << Ext;
+      return;
+    }
+
+    std::string Major, Minor;
+    auto Pos = Name.find_if(std::isdigit);
+    if (Pos != StringRef::npos) {
+      auto Next =  Name.substr(Pos);
+      Name = Name.substr(0, Pos);
+      if (!getExtensionVersion(D, MArch, Ext, Next, Major, Minor))
+        return;
+    }
+
+    // Check if duplicated extension.
+    if (std::find(AllExts.begin(), AllExts.end(), Ext) != AllExts.end()) {
+      std::string Error = "duplicated ";
+      Error += Desc;
+      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
+        << MArch << Error << Ext;
+      return;
+    }
+
+    // Extension format is correct, keep parsing the extensions.
+    // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
+    AllExts.push_back(Ext);
+  }
+
+  // Set target features.
+  // TODO: Hardware features to be handled in Support/TargetParser.cpp.
+  // TODO: Use version number when setting target features.
+  for (auto Ext : AllExts) {
+    if (!isSupportedExtension(Ext)) {
+      StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
+      std::string Error = "unsupported ";
+      Error += Desc;
+      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
+        << MArch << Error << Ext;
+      return;
+    }
+    Features.push_back(Args.MakeArgString("+" + Ext));
+  }
+}
+
 void riscv::getRISCVTargetFeatures(const Driver &D, const ArgList &Args,
                                    std::vector<StringRef> &Features) {
   if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
     StringRef MArch = A->getValue();
+
+    // RISC-V ISA strings must be lowercase.
+    if (std::any_of(std::begin(MArch), std::end(MArch),
+                    [](char c) { return isupper(c); })) {
+
+      D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
+        << "string must be lowercase";
+      return;
+    }
+
+    // ISA string must begin with rv32 or rv64.
     if (!(MArch.startswith("rv32") || MArch.startswith("rv64")) ||
         (MArch.size() < 5)) {
-      // ISA string must begin with rv32 or rv64.
-      // TODO: Improve diagnostic message.
-      D.Diag(diag::err_drv_invalid_arch_name) << MArch;
+      D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
+        << "string must begin with rv32{i,e,g} or rv64{i,g}";
       return;
     }
 
+    bool HasRV64 = MArch.startswith("rv64") ? true : false;
+
     // The canonical order specified in ISA manual.
     // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
-    StringRef StdExts = "mafdc";
-
+    StringRef StdExts = "mafdqlcbjtpvn";
     bool HasF = false, HasD = false;
     char Baseline = MArch[4];
 
-    // TODO: Add 'e' once backend supported.
+    // First letter should be 'e', 'i' or 'g'.
     switch (Baseline) {
     default:
-      // First letter should be 'e', 'i' or 'g'.
-      // TODO: Improve diagnostic message.
-      D.Diag(diag::err_drv_invalid_arch_name) << MArch;
+      D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
+        << "first letter should be 'e', 'i' or 'g'";
       return;
+    case 'e': {
+      StringRef Error;
+      // Currently LLVM does not support 'e'.
+      // Extension 'e' is not allowed in rv64.
+      if (HasRV64)
+        Error = "standard user-level extension 'e' requires 'rv32'";
+      else
+        Error = "unsupported standard user-level extension 'e'";
+      D.Diag(diag::err_drv_invalid_riscv_arch_name)
+        << MArch << Error;
+      return;
+    }
     case 'i':
       break;
     case 'g':
@@ -60,29 +260,72 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const ArgList &Args,
       break;
     }
 
-    auto StdExtsItr = StdExts.begin();
     // Skip rvxxx
     StringRef Exts = MArch.substr(5);
 
-    for (char c : Exts) {
+    // Remove non-standard extensions and supervisor-level extensions.
+    // They have 'x', 's', 'sx' prefixes. Parse them at the end.
+    // Find the very first occurrence of 's' or 'x'.
+    StringRef OtherExts;
+    size_t Pos = Exts.find_first_of("sx");
+    if (Pos != StringRef::npos) {
+      OtherExts = Exts.substr(Pos);
+      Exts = Exts.substr(0, Pos);
+    }
+
+    std::string Major, Minor;
+    if (!getExtensionVersion(D, MArch, std::string(1, Baseline),
+                             Exts, Major, Minor))
+      return;
+    
+    // TODO: Use version number when setting target features
+    // and consume the underscore '_' that might follow.
+
+    auto StdExtsItr = StdExts.begin();
+    auto StdExtsEnd = StdExts.end();
+
+    for (auto I = Exts.begin(), E = Exts.end(); I != E; ++I)  {
+      char c = *I;
+
       // Check ISA extensions are specified in the canonical order.
-      while (StdExtsItr != StdExts.end() && *StdExtsItr != c)
+      while (StdExtsItr != StdExtsEnd && *StdExtsItr != c)
         ++StdExtsItr;
 
-      if (StdExtsItr == StdExts.end()) {
-        // TODO: Improve diagnostic message.
-        D.Diag(diag::err_drv_invalid_arch_name) << MArch;
+      if (StdExtsItr == StdExtsEnd) {
+        // Either c contains a valid extension but it was not given in
+        // canonical order or it is an invalid extension.
+        StringRef Error;
+        if (StdExts.contains(c))
+          Error = "standard user-level extension not given in canonical order";
+        else
+          Error = "invalid standard user-level extension";
+        D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
+          << MArch <<  Error << std::string(1, c);
         return;
       }
 
       // Move to next char to prevent repeated letter.
       ++StdExtsItr;
 
+      if (std::next(I) != E) {
+        // Skip c.
+        std::string Next = std::string(std::next(I), E);
+        std::string Major, Minor;
+        if (!getExtensionVersion(D, MArch, std::string(1, c),
+                                 Next, Major, Minor))
+          return;
+
+        // TODO: Use version number when setting target features
+        // and consume the underscore '_' that might follow.
+      }
+
       // The order is OK, then push it into features.
       switch (c) {
       default:
-        // TODO: Improve diagnostic message.
-        D.Diag(diag::err_drv_invalid_arch_name) << MArch;
+        // Currently LLVM supports only "mafdc".
+        D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
+          << MArch << "unsupported standard user-level extension"
+          << std::string(1, c);
         return;
       case 'm':
         Features.push_back("+m");
@@ -104,13 +347,20 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const ArgList &Args,
       }
     }
 
-    // Dependency check
+    // 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: Improve diagnostic message.
     if (HasD && !HasF)
-      D.Diag(diag::err_drv_invalid_arch_name) << MArch;
+      D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
+        << "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'.
+
+    // Handle all other types of extensions.
+    getExtensionFeatures(D, Args, Features, MArch, OtherExts);
   }
 }
 
index 21d17b7..5329fe8 100644 (file)
-// RUN: %clang -target riscv32-unknown-elf -march=rv32i -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv32-unknown-elf -march=rv32im -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv32-unknown-elf -march=rv32ima -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv32-unknown-elf -march=rv32imaf -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv32-unknown-elf -march=rv32imafd -### %s -fsyntax-only 2>&1 | FileCheck %s
-
-// RUN: %clang -target riscv32-unknown-elf -march=rv32ic -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv32-unknown-elf -march=rv32imc -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv32-unknown-elf -march=rv32imac -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv32-unknown-elf -march=rv32imafc -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv32-unknown-elf -march=rv32imafdc -### %s -fsyntax-only 2>&1 | FileCheck %s
-
-// RUN: %clang -target riscv32-unknown-elf -march=rv32ia -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv32-unknown-elf -march=rv32iaf -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv32-unknown-elf -march=rv32iafd -### %s -fsyntax-only 2>&1 | FileCheck %s
-
-// RUN: %clang -target riscv32-unknown-elf -march=rv32iac -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv32-unknown-elf -march=rv32iafc -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv32-unknown-elf -march=rv32iafdc -### %s -fsyntax-only 2>&1 | FileCheck %s
-
-// RUN: %clang -target riscv32-unknown-elf -march=rv32g -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv32-unknown-elf -march=rv32gc -### %s -fsyntax-only 2>&1 | FileCheck %s
-
-// RUN: %clang -target riscv64-unknown-elf -march=rv64i -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv64-unknown-elf -march=rv64im -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv64-unknown-elf -march=rv64ima -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv64-unknown-elf -march=rv64imaf -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv64-unknown-elf -march=rv64imafd -### %s -fsyntax-only 2>&1 | FileCheck %s
-
-// RUN: %clang -target riscv64-unknown-elf -march=rv64ic -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv64-unknown-elf -march=rv64imc -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv64-unknown-elf -march=rv64imac -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv64-unknown-elf -march=rv64imafc -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv64-unknown-elf -march=rv64imafdc -### %s -fsyntax-only 2>&1 | FileCheck %s
-
-// RUN: %clang -target riscv64-unknown-elf -march=rv64ia -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv64-unknown-elf -march=rv64iaf -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv64-unknown-elf -march=rv64iafd -### %s -fsyntax-only 2>&1 | FileCheck %s
-
-// RUN: %clang -target riscv64-unknown-elf -march=rv64iac -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv64-unknown-elf -march=rv64iafc -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv64-unknown-elf -march=rv64iafdc -### %s -fsyntax-only 2>&1 | FileCheck %s
-
-// RUN: %clang -target riscv64-unknown-elf -march=rv64g -### %s -fsyntax-only 2>&1 | FileCheck %s
-// RUN: %clang -target riscv64-unknown-elf -march=rv64gc -### %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32i -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32im -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32ima -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imaf -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imafd -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32ic -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imac -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imafc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imafdc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32ia -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32iaf -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32iafd -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32iac -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32iafc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32iafdc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32g -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32gc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+
+// RUN: %clang -target riscv64-unknown-elf -march=rv64i -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64im -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64ima -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64imaf -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64imafd -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+
+// RUN: %clang -target riscv64-unknown-elf -march=rv64ic -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64imc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64imac -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64imafc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64imafdc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+
+// RUN: %clang -target riscv64-unknown-elf -march=rv64ia -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64iaf -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64iafd -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+
+// RUN: %clang -target riscv64-unknown-elf -march=rv64iac -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64iafc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64iafdc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+
+// RUN: %clang -target riscv64-unknown-elf -march=rv64g -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64gc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck %s
 
 // CHECK-NOT: error: invalid arch name '
 
-// RUN: %clang -target riscv32-unknown-elf -march=rv32 -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32 %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32 -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32 %s
 // RV32: error: invalid arch name 'rv32'
 
-// RUN: %clang -target riscv32-unknown-elf -march=rv32m -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32M %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32m -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32M %s
 // RV32M: error: invalid arch name 'rv32m'
 
-// RUN: %clang -target riscv32-unknown-elf -march=rv32id -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32ID %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32id -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32ID %s
 // RV32ID: error: invalid arch name 'rv32id'
 
-// RUN: %clang -target riscv32-unknown-elf -march=rv32l -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32L %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32l -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32L %s
 // RV32L: error: invalid arch name 'rv32l'
 
-// RUN: %clang -target riscv32-unknown-elf -march=rv32imadf -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32IMADF %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imadf -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32IMADF %s
 // RV32IMADF: error: invalid arch name 'rv32imadf'
 
-// RUN: %clang -target riscv32-unknown-elf -march=rv32imm -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32IMM %s
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imm -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32IMM %s
 // RV32IMM: error: invalid arch name 'rv32imm'
 
-// RUN: %clang -target riscv32-unknown-elf -march=RV32I -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32I-UPPER %s
+// RUN: %clang -target riscv32-unknown-elf -march=RV32I -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32I-UPPER %s
 // RV32I-UPPER: error: invalid arch name 'RV32I'
 
-// RUN: %clang -target riscv64-unknown-elf -march=rv64 -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64 %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64 -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64 %s
 // RV64: error: invalid arch name 'rv64'
 
-// RUN: %clang -target riscv64-unknown-elf -march=rv64m -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64M %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64m -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64M %s
 // RV64M: error: invalid arch name 'rv64m'
 
-// RUN: %clang -target riscv64-unknown-elf -march=rv64id -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64ID %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64id -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64ID %s
 // RV64ID: error: invalid arch name 'rv64id'
 
-// RUN: %clang -target riscv64-unknown-elf -march=rv64l -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64L %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64l -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64L %s
 // RV64L: error: invalid arch name 'rv64l'
 
-// RUN: %clang -target riscv64-unknown-elf -march=rv64imadf -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64IMADF %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64imadf -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64IMADF %s
 // RV64IMADF: error: invalid arch name 'rv64imadf'
 
-// RUN: %clang -target riscv64-unknown-elf -march=rv64imm -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64IMM %s
+// RUN: %clang -target riscv64-unknown-elf -march=rv64imm -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64IMM %s
 // RV64IMM: error: invalid arch name 'rv64imm'
 
-// RUN: %clang -target riscv64-unknown-elf -march=RV64I -### %s -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64I-UPPER %s
+// RUN: %clang -target riscv64-unknown-elf -march=RV64I -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64I-UPPER %s
 // RV64I-UPPER: error: invalid arch name 'RV64I'
+
+
+// Testing specific messages and unsupported extensions.
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32e -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32E %s
+// RV32E: error: invalid arch name 'rv32e',
+// RV32E: standard user-level extension 'e'
+
+// RUN: %clang -target riscv64-unknown-elf -march=rv64e -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV64E %s
+// RV64E: error: invalid arch name 'rv64e',
+// RV64E: standard user-level extension 'e' requires 'rv32'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imC -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-LOWER %s
+// RV32-LOWER: error: invalid arch name 'rv32imC',
+// RV32-LOWER: string must be lowercase
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32 -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-STR %s
+// RV32-STR: error: invalid arch name 'rv32',
+// RV32-STR: string must begin with rv32{i,e,g} or rv64{i,g}
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32q -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-LETTER %s
+// RV32-LETTER: error: invalid arch name 'rv32q',
+// RV32-LETTER: first letter should be 'e', 'i' or 'g'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imcq -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-ORDER %s
+// RV32-ORDER: error: invalid arch name 'rv32imcq',
+// RV32-ORDER: standard user-level extension not given in canonical order 'q'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imw -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-STD-INVAL %s
+// RV32-STD-INVAL: error: invalid arch name 'rv32imw',
+// RV32-STD-INVAL: invalid standard user-level extension 'w'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imqc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-STD %s
+// RV32-STD: error: invalid arch name 'rv32imqc',
+// RV32-STD: unsupported standard user-level extension 'q'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32xabc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32X %s
+// RV32X: error: invalid arch name 'rv32xabc',
+// RV32X: first letter should be 'e', 'i' or 'g'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32sxabc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32SX %s
+// RV32SX: error: invalid arch name 'rv32sxabc',
+// RV32SX: first letter should be 'e', 'i' or 'g'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32sabc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32S %s
+// RV32S: error: invalid arch name 'rv32sabc',
+// RV32S: first letter should be 'e', 'i' or 'g'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32ix -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32X-NAME %s
+// RV32X-NAME: error: invalid arch name 'rv32ix',
+// RV32X-NAME: non-standard user-level extension name missing after 'x'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32isx -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32SX-NAME %s
+// RV32SX-NAME: error: invalid arch name 'rv32isx',
+// RV32SX-NAME: non-standard supervisor-level extension
+// RV32SX-NAME: name missing after 'sx'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32is -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32S-NAME %s
+// RV32S-NAME: error: invalid arch name 'rv32is',
+// RV32S-NAME: standard supervisor-level extension
+// RV32S-NAME: name missing after 's'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32ix_s_sx -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32ALL-NAME %s
+// RV32ALL-NAME: error: invalid arch name 'rv32ix_s_sx',
+// RV32ALL-NAME: non-standard user-level extension
+// RV32ALL-NAME: name missing after 'x'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32ixabc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32X-UNS %s
+// RV32X-UNS: error: invalid arch name 'rv32ixabc',
+// RV32X-UNS: unsupported non-standard user-level extension 'xabc'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32isa -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32S-UNS %s
+// RV32S-UNS: error: invalid arch name 'rv32isa',
+// RV32S-UNS: unsupported standard supervisor-level extension 'sa'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32isxabc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32SX-UNS %s
+// RV32SX-UNS: error: invalid arch name 'rv32isxabc',
+// RV32SX-UNS: unsupported non-standard supervisor-level extension 'sxabc'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32ixabc_sp_sxlw -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32ALL %s
+// RV32ALL: error: invalid arch name 'rv32ixabc_sp_sxlw',
+// RV32ALL: unsupported non-standard user-level extension 'xabc'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32i20 -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-IVER %s
+// RV32-IVER: error: invalid arch name 'rv32i20', unsupported
+// RV32-IVER: version number 20 for extension 'i'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imc5 -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-CVER %s
+// RV32-CVER: error: invalid arch name 'rv32imc5', unsupported
+// RV32-CVER: version number 5 for extension 'c'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32i2p -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-IMINOR-MISS %s
+// RV32-IMINOR-MISS: error: invalid arch name 'rv32i2p',
+// RV32-IMINOR-MISS: minor version number missing after 'p' for extension 'i'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32i2p0 -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-IMINOR0 %s
+// RV32-IMINOR0: error: invalid arch name 'rv32i2p0',
+// RV32-IMINOR0: unsupported version number 2.0 for extension 'i'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32i2p1 -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-IMINOR1 %s
+// RV32-IMINOR1: error: invalid arch name 'rv32i2p1', unsupported
+// RV32-IMINOR1: version number 2.1 for extension 'i'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32ix2p -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-XMINOR-MISS %s
+// RV32-XMINOR-MISS: error: invalid arch name 'rv32ix2p',
+// RV32-XMINOR-MISS: minor version number missing after 'p' for extension 'x2p'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32is2p0 -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-SMINOR0 %s
+// RV32-SMINOR0: error: invalid arch name 'rv32is2p0',
+// RV32-SMINOR0: unsupported version number 2.0 for extension 's2p0'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32isx2p1 -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-SXMINOR1 %s
+// RV32-SXMINOR1: error: invalid arch name 'rv32isx2p1', unsupported
+// RV32-SXMINOR1: version number 2.1 for extension 'sx2p1'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32ixabc_ -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-XSEP %s
+// RV32-XSEP: error: invalid arch name 'rv32ixabc_',
+// RV32-XSEP: extension name missing after separator '_'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32ixabc_a -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-PREFIX %s
+// RV32-PREFIX: error: invalid arch name 'rv32ixabc_a',
+// RV32-PREFIX: invalid extension prefix 'a'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32isabc_xdef -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-X-ORDER %s
+// RV32-X-ORDER: error: invalid arch name 'rv32isabc_xdef',
+// RV32-X-ORDER: non-standard user-level extension not given
+// RV32-X-ORDER: in canonical order 'xdef'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32isxabc_sdef -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-S-ORDER %s
+// RV32-S-ORDER: error: invalid arch name 'rv32isxabc_sdef',
+// RV32-S-ORDER: standard supervisor-level extension not given
+// RV32-S-ORDER: in canonical order 'sdef'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32ixabc_xabc -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-XDUP %s
+// RV32-XDUP: error: invalid arch name 'rv32ixabc_xabc',
+// RV32-XDUP: duplicated non-standard user-level extension 'xabc'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32ixabc_xdef -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-X-X-INVAL %s
+// RV32-X-X-INVAL: error: invalid arch name 'rv32ixabc_xdef', unsupported
+// RV32-X-X-INVAL: non-standard user-level extension 'xabc'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32ixabc_sdef_sxghi -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-X-S-SX-INVAL %s
+// RV32-X-S-SX-INVAL: error: invalid arch name 'rv32ixabc_sdef_sxghi',
+// RV32-X-S-SX-INVAL: unsupported non-standard user-level extension 'xabc'