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

Hi Alex, the refactoring will be simple and can be done later when we need it, 
all the pieces are already parsed (type, name, major, minor) and are in 
strings,  we will only need to convert to the preferred type (enum, int, etc).
I changed the code to not error out on unsupported extension, allowing all the 
non-standard extensions to be parsed and the format errors reported. Only when 
we try to set target features I then enforce unsupported extension.
This way I could push all my tests.


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,317 @@
-// 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'
Index: lib/Driver/ToolChains/Arch/RISCV.cpp
===================================================================
--- lib/Driver/ToolChains/Arch/RISCV.cpp
+++ lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -20,32 +20,232 @@
 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 @@
       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 @@
       }
     }
 
-    // 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: 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_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 "
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to