apazos updated this revision to Diff 141043.
apazos added a comment.

updated test case


https://reviews.llvm.org/D45284

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

Index: test/Driver/riscv-arch.c
===================================================================
--- test/Driver/riscv-arch.c
+++ test/Driver/riscv-arch.c
@@ -1,89 +1,229 @@
-// 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 RUN: 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 \
+// RUNL -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=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 or rv64
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32e -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-LETTER %s
+// RV32-LETTER: error: invalid arch name 'rv32e',
+// 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: unsupported  canonical order of extension 'q'
+
+// RUN: %clang -target riscv32-unknown-elf -march=rv32imC -### %s \
+// RUn: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32-STD-INVAL %s
+// RV32-STD-INVAL: error: invalid arch name 'rv32imC',
+// RV32-STD-INVAL: unsupported standard user-level extension 'C'
+
+// 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', unsupported
+// RV32X-NAME: non-standard user-level extension name missing '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: unsupported non-standard supervisor-level extension
+// RV32SX-NAME: name missing '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:unsupported standard supervisor-level extension name missing '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: unsupported non-standard user-level extension name missing '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=rv32ixabcslw -### %s \
+// RUN: -fsyntax-only 2>&1 | FileCheck -check-prefix=RV32ALL-SEP %s
+// RV32ALL-SEP: error: invalid arch name 'rv32ixabcslw',
+// RV32ALL-SEP: unsupported multi-letter extensions, separate by
+// RV32ALL-SEP: a single underscore '_slw'
Index: lib/Driver/ToolChains/Arch/RISCV.cpp
===================================================================
--- lib/Driver/ToolChains/Arch/RISCV.cpp
+++ lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -20,31 +20,138 @@
 using namespace clang;
 using namespace llvm::opt;
 
+static bool hasExtension(StringRef In, StringRef Ext, size_t &Pos) {
+  Pos = In.find(Ext);
+  return Pos != StringRef::npos;
+}
+
+static StringRef getExtensionPrefix(StringRef Ext) {
+  if (Ext.startswith("sx"))
+    return "sx";
+  if (Ext.startswith("s"))
+    return "s";
+  if (Ext.startswith("x"))
+    return "x";
+  return StringRef();
+}
+
+static bool hasOtherExtensions(StringRef In, size_t &Pos) {
+  size_t PosSX, PosS, PosX;
+  Pos = PosSX = PosS = PosX = StringRef::npos;
+
+  bool Found = hasExtension(In, "sx", PosSX);
+  Found |= hasExtension(In, "s", PosS);
+  Found |= hasExtension(In, "x", PosX);
+
+  if (!Found)
+    return false;
+
+  auto getMinPos = [](size_t &Pos, size_t &minPos) {
+    if (Pos == StringRef::npos)
+      return;
+    if (minPos == StringRef::npos) {
+      minPos = Pos;
+      return;
+    }
+    minPos = std::min(minPos, Pos);
+  };
+
+  getMinPos(PosSX, Pos);
+  getMinPos(PosS, Pos);
+  getMinPos(PosX, Pos);
+
+  assert(Pos != StringRef::npos && "Expected an unsupported extension!");
+
+  return true;
+}
+
+// TODO: Hardware features to be handled in Support/TargetParser.cpp.
+static bool isSupportedExtension(std::vector<StringRef> &Features,
+                                 StringRef Prefix, StringRef Name) {
+  return false;
+}
+
+static void getExtensionFeatures(const Driver &D,
+                                 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("_"), -1, false);
+
+  for (StringRef Ext : Split) {
+    StringRef Prefix = getExtensionPrefix(Ext);
+    StringRef Name(Ext.substr(Prefix.size()));
+
+    StringRef Type;
+    if (Prefix == "sx")
+      Type = "non-standard supervisor-level extension";
+    else if (Prefix == "s")
+      Type = "standard supervisor-level extension";
+    else if (Prefix == "x")
+      Type = "non-standard user-level extension";
+    else {
+      Type = "invalid extension prefix";
+      D.Diag(diag::err_drv_unsupported_riscv_ext_arch_name)
+        << MArch << Type << Ext;
+      return;
+    }
+
+    size_t Pos;
+    if (hasOtherExtensions(Name, Pos)) {
+      std::string Error = "_";
+      Error += Name.substr(Pos);
+      D.Diag(diag::err_drv_unsupported_riscv_ext_arch_name)
+        << MArch
+        << "multi-letter extensions, separate by a single underscore"
+        << Error;
+      return;
+    }
+
+    if (Name.empty()) {
+      std::string Error = Type;
+      Error += " name missing";
+      D.Diag(diag::err_drv_unsupported_riscv_ext_arch_name)
+        << MArch << Error << Ext;
+      return;
+    }
+
+    if (!isSupportedExtension(Features, Prefix, Name)) {
+      D.Diag(diag::err_drv_unsupported_riscv_ext_arch_name)
+        << MArch << Type << Ext;
+      return;
+    }
+  }
+}
+
 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();
     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 or rv64";
       return;
     }
 
     // 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.
     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 'i':
       break;
@@ -61,17 +168,31 @@
     }
 
     auto StdExtsItr = StdExts.begin();
+
     // Skip rvxxx
     StringRef Exts = MArch.substr(5);
 
+    // Remove non-standard extensions (user-level and supervisor-level) and
+    // supervisor-level extensions to parse them at the end.
+    StringRef OtherExts;
+    size_t Pos;
+    if (hasOtherExtensions(Exts, Pos)) {
+      OtherExts = Exts.substr(Pos);
+      Exts = Exts.substr(0, Pos);
+    }
+
     for (char c : Exts) {
       // Check ISA extensions are specified in the canonical order.
       while (StdExtsItr != StdExts.end() && *StdExtsItr != c)
         ++StdExtsItr;
 
       if (StdExtsItr == StdExts.end()) {
-        // TODO: Improve diagnostic message.
-        D.Diag(diag::err_drv_invalid_arch_name) << MArch;
+        size_t Pos;
+        StringRef Error = "standard user-level extension";
+        if (hasExtension(StdExts, std::string(1, c), Pos))
+          Error = "canonical order of extension";
+        D.Diag(diag::err_drv_unsupported_riscv_ext_arch_name)
+          << MArch << Error << std::string(1, c);
         return;
       }
 
@@ -81,8 +202,10 @@
       // 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_unsupported_riscv_ext_arch_name)
+          << MArch << "standard user-level extension"
+          << std::string(1, c);
         return;
       case 'm':
         Features.push_back("+m");
@@ -108,9 +231,11 @@
     // 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";
+
+    getExtensionFeatures(D, Features, MArch, OtherExts);
   }
 }
 
Index: include/clang/Basic/DiagnosticDriverKinds.td
===================================================================
--- include/clang/Basic/DiagnosticDriverKinds.td
+++ include/clang/Basic/DiagnosticDriverKinds.td
@@ -24,6 +24,10 @@
 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_unsupported_riscv_ext_arch_name : Error<
+  "invalid arch name '%0', unsupported %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 "
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to