[llvm-branch-commits] [llvm] [mlir] [utils][TableGen] Implement clause aliases as alternative spellings (PR #141765)

Krzysztof Parzyszek via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed May 28 06:31:49 PDT 2025


https://github.com/kparzysz created https://github.com/llvm/llvm-project/pull/141765

Use the spellings in the generated clause parser. The functions `get<lang>ClauseKind` and `get<lang>ClauseName` are not yet updated.

The definitions of both clauses and directives now take a list of "Spelling"s instead of a single string. For example
```
def ACCC_Copyin : Clause<[Spelling<"copyin">,
                          Spelling<"present_or_copyin">,
                          Spelling<"pcopyin">]> { ... }
```

A "Spelling" is a versioned string, defaulting to "all versions".

For background information see
https://discourse.llvm.org/t/rfc-alternative-spellings-of-openmp-directives/85507

>From ba3c9184105aa18126024291dbe6401d691c3d14 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 20 May 2025 14:07:47 -0500
Subject: [PATCH] [utils][TableGen] Implement clause aliases as alternative
 spellings

Use the spellings in the generated clause parser. The functions
`get<lang>ClauseKind` and `get<lang>ClauseName` are not yet updated.

The definitions of both clauses and directives now take a list of
"Spelling"s instead of a single string. For example
```
def ACCC_Copyin : Clause<[Spelling<"copyin">,
                          Spelling<"present_or_copyin">,
                          Spelling<"pcopyin">]> { ... }
```

A "Spelling" is a versioned string, defaulting to "all versions".

For background information see
https://discourse.llvm.org/t/rfc-alternative-spellings-of-openmp-directives/85507
---
 .../llvm/Frontend/Directive/DirectiveBase.td  |  41 +-
 llvm/include/llvm/Frontend/OpenACC/ACC.td     | 146 +++---
 llvm/include/llvm/Frontend/OpenMP/OMP.td      | 496 +++++++++---------
 llvm/include/llvm/TableGen/DirectiveEmitter.h |  85 ++-
 llvm/test/TableGen/directive1.td              |  60 ++-
 llvm/test/TableGen/directive2.td              |  63 ++-
 llvm/test/TableGen/directive3.td              |  10 +-
 .../utils/TableGen/Basic/DirectiveEmitter.cpp | 115 ++--
 mlir/test/mlir-tblgen/directive-common.td     |   2 +-
 9 files changed, 582 insertions(+), 436 deletions(-)

diff --git a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
index 582da20083aee..142ba0423f251 100644
--- a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
+++ b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
@@ -51,6 +51,20 @@ class DirectiveLanguage {
   string flangClauseBaseClass = "";
 }
 
+// Base class for versioned entities.
+class Versioned<int min = 1, int max = 0x7FFFFFFF> {
+  // Mininum version number where this object is valid.
+  int minVersion = min;
+
+  // Maximum version number where this object is valid.
+  int maxVersion = max;
+}
+
+class Spelling<string s, int min = 1, int max = 0x7FFFFFFF>
+    : Versioned<min, max> {
+  string spelling = s;
+}
+
 // Some clauses take an argument from a predefined list of allowed keyword
 // values. For example, assume a clause "someclause" with an argument from
 // the list "foo", "bar", "baz". In the user source code this would look
@@ -81,12 +95,9 @@ class EnumVal<string n, int v, bit uv> {
 }
 
 // Information about a specific clause.
-class Clause<string c> {
-  // Name of the clause.
-  string name = c;
-
-  // Define aliases used in the parser.
-  list<string> aliases = [];
+class Clause<list<Spelling> ss> {
+  // Spellings of the clause.
+  list<Spelling> spellings = ss;
 
   // Optional class holding value of the clause in clang AST.
   string clangClass = "";
@@ -134,15 +145,9 @@ class Clause<string c> {
 }
 
 // Hold information about clause validity by version.
-class VersionedClause<Clause c, int min = 1, int max = 0x7FFFFFFF> {
-  // Actual clause.
+class VersionedClause<Clause c, int min = 1, int max = 0x7FFFFFFF>
+    : Versioned<min, max> {
   Clause clause = c;
-
-  // Mininum version number where this clause is valid.
-  int minVersion = min;
-
-  // Maximum version number where this clause is valid.
-  int maxVersion = max;
 }
 
 // Kinds of directive associations.
@@ -190,15 +195,15 @@ class SourceLanguage<string n> {
   string name = n;  // Name of the enum value in enum class Association.
 }
 
-// The C languages also implies C++ until there is a reason to add C++
+// The C language also implies C++ until there is a reason to add C++
 // separately.
 def L_C : SourceLanguage<"C"> {}
 def L_Fortran : SourceLanguage<"Fortran"> {}
 
 // Information about a specific directive.
-class Directive<string d> {
-  // Name of the directive. Can be composite directive sepearted by whitespace.
-  string name = d;
+class Directive<list<Spelling> ss> {
+  // Spellings of the directive.
+  list<Spelling> spellings = ss;
 
   // Clauses cannot appear twice in the three allowed lists below. Also, since
   // required implies allowed, the same clause cannot appear in both the
diff --git a/llvm/include/llvm/Frontend/OpenACC/ACC.td b/llvm/include/llvm/Frontend/OpenACC/ACC.td
index b74cd6e5642ec..65751839ceb09 100644
--- a/llvm/include/llvm/Frontend/OpenACC/ACC.td
+++ b/llvm/include/llvm/Frontend/OpenACC/ACC.td
@@ -32,64 +32,65 @@ def OpenACC : DirectiveLanguage {
 //===----------------------------------------------------------------------===//
 
 // 2.16.1
-def ACCC_Async : Clause<"async"> {
+def ACCC_Async : Clause<[Spelling<"async">]> {
   let flangClass = "ScalarIntExpr";
   let isValueOptional = true;
 }
 
 // 2.9.7
-def ACCC_Auto : Clause<"auto"> {}
+def ACCC_Auto : Clause<[Spelling<"auto">]> {}
 
 // 2.7.12
-def ACCC_Attach : Clause<"attach"> {
+def ACCC_Attach : Clause<[Spelling<"attach">]> {
   let flangClass = "AccObjectList";
 }
 
 // 2.15.1
-def ACCC_Bind : Clause<"bind"> {
+def ACCC_Bind : Clause<[Spelling<"bind">]> {
   let flangClass = "AccBindClause";
 }
 
 // 2.12
-def ACCC_Capture : Clause<"capture"> {
+def ACCC_Capture : Clause<[Spelling<"capture">]> {
 }
 
 // 2.9.1
-def ACCC_Collapse : Clause<"collapse"> {
+def ACCC_Collapse : Clause<[Spelling<"collapse">]> {
   let flangClass = "AccCollapseArg";
 }
 
 // 2.7.6
-def ACCC_Copy : Clause<"copy"> {
+def ACCC_Copy
+    : Clause<[Spelling<"copy">, Spelling<"present_or_copy">,
+              Spelling<"pcopy">]> {
   let flangClass = "AccObjectList";
-  let aliases = ["present_or_copy", "pcopy"];
 }
 
 // 2.7.7
-def ACCC_Copyin : Clause<"copyin"> {
+def ACCC_Copyin : Clause<[Spelling<"copyin">, Spelling<"present_or_copyin">,
+                          Spelling<"pcopyin">]> {
   let flangClass = "AccObjectListWithModifier";
   let clangAccSpelling = "CopyIn";
-  let aliases = ["present_or_copyin", "pcopyin"];
 }
 
 // 2.7.8
-def ACCC_Copyout : Clause<"copyout"> {
+def ACCC_Copyout : Clause<[Spelling<"copyout">, Spelling<"present_or_copyout">,
+                           Spelling<"pcopyout">]> {
   let flangClass = "AccObjectListWithModifier";
   let clangAccSpelling = "CopyOut";
-  let aliases = ["present_or_copyout", "pcopyout"];
 }
 
 // 2.7.9
-def ACCC_Create : Clause<"create"> {
+def ACCC_Create : Clause<[Spelling<"create">, Spelling<"present_or_create">,
+                          Spelling<"pcreate">]> {
   let flangClass = "AccObjectListWithModifier";
-  let aliases = ["present_or_create", "pcreate"];
 }
 
 // 2.5.16
 def ACC_Default_none : EnumVal<"none", 1, 1> { let isDefault = 1; }
 def ACC_Default_present : EnumVal<"present", 0, 1> {}
 
-def ACCC_Default : Clause<"default"> {
+def ACCC_Default : Clause<[Spelling<"default">]> {
   let flangClass = "AccDefaultClause";
   let enumClauseValue = "DefaultValue";
   let allowedClauseValues = [
@@ -99,174 +100,173 @@ def ACCC_Default : Clause<"default"> {
 }
 
 // 2.14.3
-def ACCC_DefaultAsync : Clause<"default_async"> {
+def ACCC_DefaultAsync : Clause<[Spelling<"default_async">]> {
   let flangClass = "ScalarIntExpr";
 }
 
 // 2.7.11
-def ACCC_Delete : Clause<"delete"> {
+def ACCC_Delete : Clause<[Spelling<"delete">]> {
   let flangClass = "AccObjectList";
 }
 
 // 2.7.13
-def ACCC_Detach : Clause<"detach"> {
+def ACCC_Detach : Clause<[Spelling<"detach">]> {
   let flangClass = "AccObjectList";
 }
 
 // 2.14.4
-def ACCC_Device : Clause<"device"> {
+def ACCC_Device : Clause<[Spelling<"device">]> {
   let flangClass = "AccObjectList";
 }
 
 // 2.14.1 - 2.14.2
-def ACCC_DeviceNum : Clause<"device_num">  {
+def ACCC_DeviceNum : Clause<[Spelling<"device_num">]>  {
   let flangClass = "ScalarIntExpr";
 }
 
 // 2.7.4
-def ACCC_DevicePtr : Clause<"deviceptr"> {
+def ACCC_DevicePtr : Clause<[Spelling<"deviceptr">]> {
   let flangClass = "AccObjectList";
   let clangAccSpelling = "DevicePtr";
 }
 
 // 2.13.1
-def ACCC_DeviceResident : Clause<"device_resident"> {
+def ACCC_DeviceResident : Clause<[Spelling<"device_resident">]> {
   let flangClass = "AccObjectList";
 }
 
 // 2.4
-def ACCC_DeviceType : Clause<"device_type"> {
+def ACCC_DeviceType : Clause<[Spelling<"device_type">, Spelling<"dtype">]> {
   let flangClass = "AccDeviceTypeExprList";
   let defaultValue = "*";
-  let aliases = ["dtype"];
 }
 
 // 2.6.6
-def ACCC_Finalize : Clause<"finalize"> {}
+def ACCC_Finalize : Clause<[Spelling<"finalize">]> {}
 
 // 2.5.14
-def ACCC_FirstPrivate : Clause<"firstprivate"> {
+def ACCC_FirstPrivate : Clause<[Spelling<"firstprivate">]> {
   let flangClass = "AccObjectList";
   let clangAccSpelling = "FirstPrivate";
 }
 
 // 2.9.2
-def ACCC_Gang : Clause<"gang"> {
+def ACCC_Gang : Clause<[Spelling<"gang">]> {
   let flangClass = "AccGangArgList";
   let isValueOptional = true;
 }
 
 // 2.14.4
-def ACCC_Host : Clause<"host"> {
+def ACCC_Host : Clause<[Spelling<"host">]> {
   let flangClass = "AccObjectList";
 }
 
 // 2.5.6
-def ACCC_If : Clause <"if"> {
+def ACCC_If : Clause<[Spelling<"if">]> {
   let flangClass = "ScalarExpr";
 }
 
 // 2.14.4
-def ACCC_IfPresent : Clause<"if_present"> {}
+def ACCC_IfPresent : Clause<[Spelling<"if_present">]> {}
 
 // 2.9.6
-def ACCC_Independent : Clause<"independent"> {}
+def ACCC_Independent : Clause<[Spelling<"independent">]> {}
 
 // 2.13.3
-def ACCC_Link : Clause<"link"> {
+def ACCC_Link : Clause<[Spelling<"link">]> {
   let flangClass = "AccObjectList";
 }
 
 // 2.7.10
-def ACCC_NoCreate : Clause<"no_create"> {
+def ACCC_NoCreate : Clause<[Spelling<"no_create">]> {
   let flangClass = "AccObjectList";
 }
 
 // 2.15.1
-def ACCC_NoHost : Clause<"nohost"> { 
-  let clangAccSpelling = "NoHost"; 
+def ACCC_NoHost : Clause<[Spelling<"nohost">]> {
+  let clangAccSpelling = "NoHost";
 }
 
 // 2.5.10
-def ACCC_NumGangs : Clause<"num_gangs"> {
+def ACCC_NumGangs : Clause<[Spelling<"num_gangs">]> {
   let flangClass = "ScalarIntExpr";
   let isValueList = 1;
 }
 
 // 2.5.11
-def ACCC_NumWorkers : Clause<"num_workers"> {
+def ACCC_NumWorkers : Clause<[Spelling<"num_workers">]> {
   let flangClass = "ScalarIntExpr";
 }
 
 // 2.7.5
-def ACCC_Present : Clause<"present"> {
+def ACCC_Present : Clause<[Spelling<"present">]> {
   let flangClass = "AccObjectList";
 }
 
 // 2.5.13
-def ACCC_Private : Clause<"private"> {
+def ACCC_Private : Clause<[Spelling<"private">]> {
   let flangClass = "AccObjectList";
 }
 
 // 2.9.8
-def ACCC_Tile : Clause <"tile"> {
+def ACCC_Tile : Clause<[Spelling<"tile">]> {
   let flangClass = "AccTileExprList";
 }
 
 // 2.8.1
-def ACCC_UseDevice : Clause <"use_device"> {
+def ACCC_UseDevice : Clause<[Spelling<"use_device">]> {
   let flangClass = "AccObjectList";
 }
 
 // 2.12
-def ACCC_Read : Clause<"read"> {}
+def ACCC_Read : Clause<[Spelling<"read">]> {}
 
 // 2.5.15
-def ACCC_Reduction : Clause<"reduction"> {
+def ACCC_Reduction : Clause<[Spelling<"reduction">]> {
   let flangClass = "AccObjectListWithReduction";
 }
 
 // 2.5.7
-def ACCC_Self : Clause<"self"> {
+def ACCC_Self : Clause<[Spelling<"self">]> {
   let flangClass = "AccSelfClause";
   let isValueOptional = true;
 }
 
 // 2.9.5
-def ACCC_Seq : Clause<"seq"> {}
+def ACCC_Seq : Clause<[Spelling<"seq">]> {}
 
 // Non-standard extension
-def ACCC_ShortLoop : Clause<"shortloop"> {}
+def ACCC_ShortLoop : Clause<[Spelling<"shortloop">]> {}
 
 // 2.9.4
-def ACCC_Vector : Clause<"vector"> {
+def ACCC_Vector : Clause<[Spelling<"vector">]> {
   let flangClass = "ScalarIntExpr";
   let isValueOptional = true;
   let prefix = "length";
 }
 
 // 2.5.12
-def ACCC_VectorLength : Clause<"vector_length"> {
+def ACCC_VectorLength : Clause<[Spelling<"vector_length">]> {
   let flangClass = "ScalarIntExpr";
 }
 
 // 2.16.2
-def ACCC_Wait : Clause<"wait"> {
+def ACCC_Wait : Clause<[Spelling<"wait">]> {
   let flangClass = "AccWaitArgument";
   let isValueOptional = true;
 }
 
 // 2.9.3
-def ACCC_Worker: Clause<"worker"> {
+def ACCC_Worker: Clause<[Spelling<"worker">]> {
   let flangClass = "ScalarIntExpr";
   let isValueOptional = true;
   let prefix = "num";
 }
 
 // 2.12
-def ACCC_Write : Clause<"write"> {}
+def ACCC_Write : Clause<[Spelling<"write">]> {}
 
-def ACCC_Unknown : Clause<"unknown"> {
+def ACCC_Unknown : Clause<[Spelling<"unknown">]> {
   let isDefault = true;
 }
 
@@ -275,14 +275,14 @@ def ACCC_Unknown : Clause<"unknown"> {
 //===----------------------------------------------------------------------===//
 
 // 2.12
-def ACC_Atomic : Directive<"atomic"> {
+def ACC_Atomic : Directive<[Spelling<"atomic">]> {
   let allowedOnceClauses = [VersionedClause<ACCC_If, 34>];
   let association = AS_Block;
   let category = CA_Executable;
 }
 
 // 2.6.5
-def ACC_Data : Directive<"data"> {
+def ACC_Data : Directive<[Spelling<"data">]> {
   let allowedOnceClauses = [
     VersionedClause<ACCC_If>,
     VersionedClause<ACCC_Default>
@@ -308,7 +308,7 @@ def ACC_Data : Directive<"data"> {
 }
 
 // 2.13
-def ACC_Declare : Directive<"declare"> {
+def ACC_Declare : Directive<[Spelling<"declare">]> {
   let allowedClauses = [
     VersionedClause<ACCC_Copy>,
     VersionedClause<ACCC_Copyin>,
@@ -324,7 +324,7 @@ def ACC_Declare : Directive<"declare"> {
 }
 
 // 2.5.3
-def ACC_Kernels : Directive<"kernels"> {
+def ACC_Kernels : Directive<[Spelling<"kernels">]> {
   let allowedClauses = [VersionedClause<ACCC_Async>,
                         VersionedClause<ACCC_Attach>,
                         VersionedClause<ACCC_Copy>,
@@ -347,7 +347,7 @@ def ACC_Kernels : Directive<"kernels"> {
 }
 
 // 2.5.1
-def ACC_Parallel : Directive<"parallel"> {
+def ACC_Parallel : Directive<[Spelling<"parallel">]> {
   let allowedClauses = [
     VersionedClause<ACCC_Attach>,
     VersionedClause<ACCC_Async>,
@@ -377,7 +377,7 @@ def ACC_Parallel : Directive<"parallel"> {
 }
 
 // 2.5.2
-def ACC_Serial : Directive<"serial"> {
+def ACC_Serial : Directive<[Spelling<"serial">]> {
   // Spec line 950-951: clause is as for the parallel construct except that the
   // num_gangs, num_workers, and vector_length clauses are not permitted.
   let allowedClauses = [VersionedClause<ACCC_Async>,
@@ -402,7 +402,7 @@ def ACC_Serial : Directive<"serial"> {
 }
 
 // 2.9
-def ACC_Loop : Directive<"loop"> {
+def ACC_Loop : Directive<[Spelling<"loop">]> {
   let allowedClauses = [
     VersionedClause<ACCC_DeviceType>,
     VersionedClause<ACCC_Private>,
@@ -424,13 +424,13 @@ def ACC_Loop : Directive<"loop"> {
 }
 
 // 2.10
-def ACC_Cache : Directive<"cache"> {
+def ACC_Cache : Directive<[Spelling<"cache">]> {
   let association = AS_None;
   let category = CA_Executable;
 }
 
 // 2.14.1
-def ACC_Init : Directive<"init"> {
+def ACC_Init : Directive<[Spelling<"init">]> {
   let allowedOnceClauses = [VersionedClause<ACCC_DeviceNum>,
                             VersionedClause<ACCC_If>];
   let allowedClauses = [VersionedClause<ACCC_DeviceType>];
@@ -439,7 +439,7 @@ def ACC_Init : Directive<"init"> {
 }
 
 // 2.15.1
-def ACC_Routine : Directive<"routine"> {
+def ACC_Routine : Directive<[Spelling<"routine">]> {
   let allowedClauses = [
     VersionedClause<ACCC_Bind>,
     VersionedClause<ACCC_DeviceType>,
@@ -456,7 +456,7 @@ def ACC_Routine : Directive<"routine"> {
 }
 
 // 2.14.3
-def ACC_Set : Directive<"set"> {
+def ACC_Set : Directive<[Spelling<"set">]> {
   let allowedOnceClauses = [
     VersionedClause<ACCC_DefaultAsync>,
     VersionedClause<ACCC_DeviceNum>,
@@ -476,7 +476,7 @@ def ACC_Set : Directive<"set"> {
 }
 
 // 2.14.2
-def ACC_Shutdown : Directive<"shutdown"> {
+def ACC_Shutdown : Directive<[Spelling<"shutdown">]> {
   let allowedOnceClauses = [VersionedClause<ACCC_DeviceNum>,
                             VersionedClause<ACCC_If>];
   let allowedClauses = [VersionedClause<ACCC_DeviceType>];
@@ -485,7 +485,7 @@ def ACC_Shutdown : Directive<"shutdown"> {
 }
 
 // 2.14.4
-def ACC_Update : Directive<"update"> {
+def ACC_Update : Directive<[Spelling<"update">]> {
   let allowedClauses = [VersionedClause<ACCC_DeviceType>,
                         VersionedClause<ACCC_IfPresent>,
                         VersionedClause<ACCC_Wait>];
@@ -501,7 +501,7 @@ def ACC_Update : Directive<"update"> {
 }
 
 // 2.16.3
-def ACC_Wait : Directive<"wait"> {
+def ACC_Wait : Directive<[Spelling<"wait">]> {
   let allowedOnceClauses = [
     VersionedClause<ACCC_Async>,
     VersionedClause<ACCC_If>
@@ -511,7 +511,7 @@ def ACC_Wait : Directive<"wait"> {
 }
 
 // 2.14.6
-def ACC_EnterData : Directive<"enter data"> {
+def ACC_EnterData : Directive<[Spelling<"enter data">]> {
   let allowedClauses = [
     VersionedClause<ACCC_Wait>
   ];
@@ -529,7 +529,7 @@ def ACC_EnterData : Directive<"enter data"> {
 }
 
 // 2.14.7
-def ACC_ExitData : Directive<"exit data"> {
+def ACC_ExitData : Directive<[Spelling<"exit data">]> {
   let allowedClauses = [VersionedClause<ACCC_Finalize>,
                         VersionedClause<ACCC_Wait>];
   let allowedOnceClauses = [VersionedClause<ACCC_Async>,
@@ -544,7 +544,7 @@ def ACC_ExitData : Directive<"exit data"> {
 }
 
 // 2.8
-def ACC_HostData : Directive<"host_data"> {
+def ACC_HostData : Directive<[Spelling<"host_data">]> {
   let allowedClauses = [VersionedClause<ACCC_IfPresent>];
   let allowedOnceClauses = [VersionedClause<ACCC_If>];
   let requiredClauses = [
@@ -555,7 +555,7 @@ def ACC_HostData : Directive<"host_data"> {
 }
 
 // 2.11
-def ACC_KernelsLoop : Directive<"kernels loop"> {
+def ACC_KernelsLoop : Directive<[Spelling<"kernels loop">]> {
   let allowedClauses = [VersionedClause<ACCC_Async>,
                         VersionedClause<ACCC_Attach>,
                         VersionedClause<ACCC_Collapse>,
@@ -591,7 +591,7 @@ def ACC_KernelsLoop : Directive<"kernels loop"> {
 }
 
 // 2.11
-def ACC_ParallelLoop : Directive<"parallel loop"> {
+def ACC_ParallelLoop : Directive<[Spelling<"parallel loop">]> {
   let allowedClauses = [VersionedClause<ACCC_Async>,
                         VersionedClause<ACCC_Attach>,
                         VersionedClause<ACCC_Collapse>,
@@ -628,7 +628,7 @@ def ACC_ParallelLoop : Directive<"parallel loop"> {
 }
 
 // 2.11
-def ACC_SerialLoop : Directive<"serial loop"> {
+def ACC_SerialLoop : Directive<[Spelling<"serial loop">]> {
   let allowedClauses = [VersionedClause<ACCC_Async>,
                         VersionedClause<ACCC_Attach>,
                         VersionedClause<ACCC_Collapse>,
@@ -661,7 +661,7 @@ def ACC_SerialLoop : Directive<"serial loop"> {
   let category = CA_Executable;
 }
 
-def ACC_Unknown : Directive<"unknown"> {
+def ACC_Unknown : Directive<[Spelling<"unknown">]> {
   let isDefault = true;
   let association = AS_None;
   let category = CA_Utility;
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index cc9e038dc533c..027692275b63b 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -32,47 +32,48 @@ def OpenMP : DirectiveLanguage {
 // Sorted alphabetically wrt clause spelling.
 //===----------------------------------------------------------------------===//
 
-def OMPC_Absent : Clause<"absent"> {
+def OMPC_Absent : Clause<[Spelling<"absent">]> {
   let clangClass = "OMPAbsentClause";
   let flangClass = "OmpAbsentClause";
 }
-def OMPC_Acquire : Clause<"acquire"> {
+def OMPC_Acquire : Clause<[Spelling<"acquire">]> {
   let clangClass = "OMPAcquireClause";
 }
-def OMPC_AcqRel : Clause<"acq_rel"> {
+def OMPC_AcqRel : Clause<[Spelling<"acq_rel">]> {
   let clangClass = "OMPAcqRelClause";
 }
-def OMPC_AdjustArgs : Clause<"adjust_args"> {
+def OMPC_AdjustArgs : Clause<[Spelling<"adjust_args">]> {
   let flangClass = "OmpAdjustArgsClause";
 }
-def OMPC_Affinity : Clause<"affinity"> {
+def OMPC_Affinity : Clause<[Spelling<"affinity">]> {
   let clangClass = "OMPAffinityClause";
   let flangClass = "OmpAffinityClause";
 }
-def OMPC_Align : Clause<"align"> {
+def OMPC_Align : Clause<[Spelling<"align">]> {
   let clangClass = "OMPAlignClause";
   let flangClass = "OmpAlignClause";
 }
-def OMPC_Aligned : Clause<"aligned"> {
+def OMPC_Aligned : Clause<[Spelling<"aligned">]> {
   let clangClass = "OMPAlignedClause";
   let flangClass = "OmpAlignedClause";
 }
-def OMPC_Allocate : Clause<"allocate"> {
+def OMPC_Allocate : Clause<[Spelling<"allocate">]> {
   let clangClass = "OMPAllocateClause";
   let flangClass = "OmpAllocateClause";
 }
-def OMPC_Allocator : Clause<"allocator"> {
+def OMPC_Allocator : Clause<[Spelling<"allocator">]> {
   let clangClass = "OMPAllocatorClause";
   let flangClass = "ScalarIntExpr";
 }
-def OMPC_AppendArgs : Clause<"append_args"> {
+def OMPC_AppendArgs : Clause<[Spelling<"append_args">]> {
   let flangClass = "OmpAppendArgsClause";
 }
-def OMPC_At : Clause<"at"> {
+def OMPC_At : Clause<[Spelling<"at">]> {
   let clangClass = "OMPAtClause";
   let flangClass = "OmpAtClause";
 }
-def OMPC_AtomicDefaultMemOrder : Clause<"atomic_default_mem_order"> {
+def OMPC_AtomicDefaultMemOrder
+    : Clause<[Spelling<"atomic_default_mem_order">]> {
   let clangClass = "OMPAtomicDefaultMemOrderClause";
   let flangClass = "OmpAtomicDefaultMemOrderClause";
 }
@@ -80,7 +81,7 @@ def OMPC_AtomicDefaultMemOrder : Clause<"atomic_default_mem_order"> {
 def OMP_BIND_parallel : EnumVal<"parallel",1,1> {}
 def OMP_BIND_teams : EnumVal<"teams",2,1> {}
 def OMP_BIND_thread : EnumVal<"thread",3,1> { let isDefault = true; }
-def OMPC_Bind : Clause<"bind"> {
+def OMPC_Bind : Clause<[Spelling<"bind">]> {
   let clangClass = "OMPBindClause";
   let flangClass = "OmpBindClause";
   let enumClauseValue = "BindKind";
@@ -98,7 +99,8 @@ def OMP_CANCELLATION_CONSTRUCT_Taskgroup : EnumVal<"taskgroup", 4, 1> {}
 def OMP_CANCELLATION_CONSTRUCT_None : EnumVal<"none", 5, 0> {
   let isDefault = 1;
 }
-def OMPC_CancellationConstructType : Clause<"cancellation_construct_type"> {
+def OMPC_CancellationConstructType
+    : Clause<[Spelling<"cancellation_construct_type">]> {
   let enumClauseValue = "CancellationConstructType";
   let allowedClauseValues = [
     OMP_CANCELLATION_CONSTRUCT_Parallel,
@@ -110,109 +112,109 @@ def OMPC_CancellationConstructType : Clause<"cancellation_construct_type"> {
   let flangClass = "OmpCancellationConstructTypeClause";
   let skipFlangUnparser = true;
 }
-def OMPC_Contains : Clause<"contains"> {
+def OMPC_Contains : Clause<[Spelling<"contains">]> {
   let clangClass = "OMPContainsClause";
   let flangClass = "OmpContainsClause";
 }
-def OMPC_Capture : Clause<"capture"> {
+def OMPC_Capture : Clause<[Spelling<"capture">]> {
   let clangClass = "OMPCaptureClause";
 }
-def OMPC_Collapse : Clause<"collapse"> {
+def OMPC_Collapse : Clause<[Spelling<"collapse">]> {
   let clangClass = "OMPCollapseClause";
   let flangClass = "ScalarIntConstantExpr";
 }
-def OMPC_Compare : Clause<"compare"> {
+def OMPC_Compare : Clause<[Spelling<"compare">]> {
   let clangClass = "OMPCompareClause";
 }
-def OMPC_Copyin : Clause<"copyin"> {
+def OMPC_Copyin : Clause<[Spelling<"copyin">]> {
   let clangClass = "OMPCopyinClause";
   let flangClass = "OmpObjectList";
 }
-def OMPC_CopyPrivate : Clause<"copyprivate"> {
+def OMPC_CopyPrivate : Clause<[Spelling<"copyprivate">]> {
   let clangClass = "OMPCopyprivateClause";
   let flangClass = "OmpObjectList";
 }
-def OMPC_Default : Clause<"default"> {
+def OMPC_Default : Clause<[Spelling<"default">]> {
   let clangClass = "OMPDefaultClause";
   let flangClass = "OmpDefaultClause";
 }
-def OMPC_DefaultMap : Clause<"defaultmap"> {
+def OMPC_DefaultMap : Clause<[Spelling<"defaultmap">]> {
   let clangClass = "OMPDefaultmapClause";
   let flangClass = "OmpDefaultmapClause";
 }
-def OMPC_Depend : Clause<"depend"> {
+def OMPC_Depend : Clause<[Spelling<"depend">]> {
   let clangClass = "OMPDependClause";
   let flangClass = "OmpDependClause";
 }
-def OMPC_Depobj : Clause<"depobj"> {
+def OMPC_Depobj : Clause<[Spelling<"depobj">]> {
   let clangClass = "OMPDepobjClause";
   let isImplicit = true;
 }
-def OMPC_Destroy : Clause<"destroy"> {
+def OMPC_Destroy : Clause<[Spelling<"destroy">]> {
   let clangClass = "OMPDestroyClause";
   let flangClass = "OmpDestroyClause";
   let isValueOptional = true;
 }
-def OMPC_Detach : Clause<"detach"> {
+def OMPC_Detach : Clause<[Spelling<"detach">]> {
   let clangClass = "OMPDetachClause";
   let flangClass = "OmpDetachClause";
 }
-def OMPC_Device : Clause<"device"> {
+def OMPC_Device : Clause<[Spelling<"device">]> {
   let clangClass = "OMPDeviceClause";
   let flangClass = "OmpDeviceClause";
 }
-def OMPC_DeviceType : Clause<"device_type"> {
+def OMPC_DeviceType : Clause<[Spelling<"device_type">]> {
   let flangClass = "OmpDeviceTypeClause";
 }
-def OMPC_DistSchedule : Clause<"dist_schedule"> {
+def OMPC_DistSchedule : Clause<[Spelling<"dist_schedule">]> {
   let clangClass = "OMPDistScheduleClause";
   let flangClass = "ScalarIntExpr";
   let isValueOptional = true;
 }
-def OMPC_Doacross : Clause<"doacross"> {
+def OMPC_Doacross : Clause<[Spelling<"doacross">]> {
   let clangClass = "OMPDoacrossClause";
   let flangClass = "OmpDoacrossClause";
 }
-def OMPC_DynamicAllocators : Clause<"dynamic_allocators"> {
+def OMPC_DynamicAllocators : Clause<[Spelling<"dynamic_allocators">]> {
   let clangClass = "OMPDynamicAllocatorsClause";
 }
-def OMPC_Enter : Clause<"enter"> {
+def OMPC_Enter : Clause<[Spelling<"enter">]> {
   let flangClass = "OmpObjectList";
 }
-def OMPC_Exclusive : Clause<"exclusive"> {
+def OMPC_Exclusive : Clause<[Spelling<"exclusive">]> {
   let clangClass = "OMPExclusiveClause";
   let flangClass = "OmpObjectList";
 }
-def OMPC_Fail : Clause<"fail"> {
+def OMPC_Fail : Clause<[Spelling<"fail">]> {
   let clangClass = "OMPFailClause";
   let flangClass = "OmpFailClause";
 }
-def OMPC_Filter : Clause<"filter"> {
+def OMPC_Filter : Clause<[Spelling<"filter">]> {
   let clangClass = "OMPFilterClause";
   let flangClass = "ScalarIntExpr";
 }
-def OMPC_Final : Clause<"final"> {
+def OMPC_Final : Clause<[Spelling<"final">]> {
   let clangClass = "OMPFinalClause";
   let flangClass = "ScalarLogicalExpr";
 }
-def OMPC_FirstPrivate : Clause<"firstprivate"> {
+def OMPC_FirstPrivate : Clause<[Spelling<"firstprivate">]> {
   let clangClass = "OMPFirstprivateClause";
   let flangClass = "OmpObjectList";
 }
-def OMPC_Flush : Clause<"flush"> {
+def OMPC_Flush : Clause<[Spelling<"flush">]> {
   let clangClass = "OMPFlushClause";
   let isImplicit = true;
 }
-def OMPC_From : Clause<"from"> {
+def OMPC_From : Clause<[Spelling<"from">]> {
   let clangClass = "OMPFromClause";
   let flangClass = "OmpFromClause";
 }
-def OMPC_Full: Clause<"full"> {
+def OMPC_Full: Clause<[Spelling<"full">]> {
   let clangClass = "OMPFullClause";
 }
 def OMP_GRAINSIZE_Strict : EnumVal<"strict", 1, 1> {}
 def OMP_GRAINSIZE_Unknown : EnumVal<"unknown", 2, 0> { let isDefault = 1; }
-def OMPC_GrainSize : Clause<"grainsize"> {
+def OMPC_GrainSize : Clause<[Spelling<"grainsize">]> {
   let clangClass = "OMPGrainsizeClause";
   let flangClass = "OmpGrainsizeClause";
   let enumClauseValue = "GrainsizeType";
@@ -221,61 +223,61 @@ def OMPC_GrainSize : Clause<"grainsize"> {
     OMP_GRAINSIZE_Unknown
   ];
 }
-def OMPC_HasDeviceAddr : Clause<"has_device_addr"> {
+def OMPC_HasDeviceAddr : Clause<[Spelling<"has_device_addr">]> {
   let clangClass = "OMPHasDeviceAddrClause";
   let flangClass = "OmpObjectList";
 }
-def OMPC_Hint : Clause<"hint"> {
+def OMPC_Hint : Clause<[Spelling<"hint">]> {
   let clangClass = "OMPHintClause";
   let flangClass = "OmpHintClause";
 }
-def OMPC_Holds : Clause<"holds"> {
+def OMPC_Holds : Clause<[Spelling<"holds">]> {
   let clangClass = "OMPHoldsClause";
   let flangClass = "OmpHoldsClause";
 }
-def OMPC_If : Clause<"if"> {
+def OMPC_If : Clause<[Spelling<"if">]> {
   let clangClass = "OMPIfClause";
   let flangClass = "OmpIfClause";
 }
-def OMPC_Inbranch : Clause<"inbranch"> {
+def OMPC_Inbranch : Clause<[Spelling<"inbranch">]> {
 }
-def OMPC_Inclusive : Clause<"inclusive"> {
+def OMPC_Inclusive : Clause<[Spelling<"inclusive">]> {
   let clangClass = "OMPInclusiveClause";
   let flangClass = "OmpObjectList";
 }
-def OMPC_Indirect : Clause<"indirect"> {
+def OMPC_Indirect : Clause<[Spelling<"indirect">]> {
 }
-def OMPC_Init : Clause<"init"> {
+def OMPC_Init : Clause<[Spelling<"init">]> {
   let clangClass = "OMPInitClause";
   let flangClass = "OmpInitClause";
 }
-def OMPC_Initializer : Clause<"initializer"> {
+def OMPC_Initializer : Clause<[Spelling<"initializer">]> {
   let flangClass = "OmpInitializerClause";
 }
-def OMPC_InReduction : Clause<"in_reduction"> {
+def OMPC_InReduction : Clause<[Spelling<"in_reduction">]> {
   let clangClass = "OMPInReductionClause";
   let flangClass = "OmpInReductionClause";
 }
-def OMPC_IsDevicePtr : Clause<"is_device_ptr"> {
+def OMPC_IsDevicePtr : Clause<[Spelling<"is_device_ptr">]> {
   let clangClass = "OMPIsDevicePtrClause";
   let flangClass = "OmpObjectList";
 }
-def OMPC_LastPrivate : Clause<"lastprivate"> {
+def OMPC_LastPrivate : Clause<[Spelling<"lastprivate">]> {
   let clangClass = "OMPLastprivateClause";
   let flangClass = "OmpLastprivateClause";
 }
-def OMPC_Linear : Clause<"linear"> {
+def OMPC_Linear : Clause<[Spelling<"linear">]> {
   let clangClass = "OMPLinearClause";
   let flangClass = "OmpLinearClause";
 }
-def OMPC_Link : Clause<"link"> {
+def OMPC_Link : Clause<[Spelling<"link">]> {
   let flangClass = "OmpObjectList";
 }
-def OMPC_Map : Clause<"map"> {
+def OMPC_Map : Clause<[Spelling<"map">]> {
   let clangClass = "OMPMapClause";
   let flangClass = "OmpMapClause";
 }
-def OMPC_Match : Clause<"match"> {
+def OMPC_Match : Clause<[Spelling<"match">]> {
   let flangClass = "OmpMatchClause";
 }
 def OMP_MEMORY_ORDER_SeqCst : EnumVal<"seq_cst", 1, 1> {}
@@ -286,7 +288,7 @@ def OMP_MEMORY_ORDER_Relaxed : EnumVal<"relaxed", 5, 1> {}
 def OMP_MEMORY_ORDER_Default : EnumVal<"default", 6, 0> {
   let isDefault = 1;
 }
-def OMPC_MemoryOrder : Clause<"memory_order"> {
+def OMPC_MemoryOrder : Clause<[Spelling<"memory_order">]> {
   let enumClauseValue = "MemoryOrderKind";
   let allowedClauseValues = [
     OMP_MEMORY_ORDER_SeqCst,
@@ -297,49 +299,49 @@ def OMPC_MemoryOrder : Clause<"memory_order"> {
     OMP_MEMORY_ORDER_Default
   ];
 }
-def OMPC_Mergeable : Clause<"mergeable"> {
+def OMPC_Mergeable : Clause<[Spelling<"mergeable">]> {
   let clangClass = "OMPMergeableClause";
 }
-def OMPC_Message : Clause<"message"> {
+def OMPC_Message : Clause<[Spelling<"message">]> {
   let clangClass = "OMPMessageClause";
   let flangClass = "OmpMessageClause";
 }
-def OMPC_NoOpenMP : Clause<"no_openmp"> {
+def OMPC_NoOpenMP : Clause<[Spelling<"no_openmp">]> {
   let clangClass = "OMPNoOpenMPClause";
 }
-def OMPC_NoOpenMPRoutines : Clause<"no_openmp_routines"> {
+def OMPC_NoOpenMPRoutines : Clause<[Spelling<"no_openmp_routines">]> {
   let clangClass = "OMPNoOpenMPRoutinesClause";
 }
-def OMPC_NoOpenMPConstructs : Clause<"no_openmp_constructs"> {
+def OMPC_NoOpenMPConstructs : Clause<[Spelling<"no_openmp_constructs">]> {
   let clangClass = "OMPNoOpenMPConstructsClause";
 }
-def OMPC_NoParallelism : Clause<"no_parallelism"> {
+def OMPC_NoParallelism : Clause<[Spelling<"no_parallelism">]> {
   let clangClass = "OMPNoParallelismClause";
 }
-def OMPC_Nocontext : Clause<"nocontext"> {
+def OMPC_Nocontext : Clause<[Spelling<"nocontext">]> {
   let clangClass = "OMPNocontextClause";
   let flangClass = "ScalarLogicalExpr";
 }
-def OMPC_NoGroup : Clause<"nogroup"> {
+def OMPC_NoGroup : Clause<[Spelling<"nogroup">]> {
   let clangClass = "OMPNogroupClause";
 }
-def OMPC_NonTemporal : Clause<"nontemporal"> {
+def OMPC_NonTemporal : Clause<[Spelling<"nontemporal">]> {
   let clangClass = "OMPNontemporalClause";
   let flangClass = "Name";
   let isValueList = true;
 }
-def OMPC_Notinbranch : Clause<"notinbranch"> {
+def OMPC_Notinbranch : Clause<[Spelling<"notinbranch">]> {
 }
-def OMPC_Novariants : Clause<"novariants"> {
+def OMPC_Novariants : Clause<[Spelling<"novariants">]> {
   let clangClass = "OMPNovariantsClause";
   let flangClass = "ScalarLogicalExpr";
 }
-def OMPC_NoWait : Clause<"nowait"> {
+def OMPC_NoWait : Clause<[Spelling<"nowait">]> {
   let clangClass = "OMPNowaitClause";
 }
 def OMP_NUMTASKS_Strict : EnumVal<"strict", 1, 1> {}
 def OMP_NUMTASKS_Unknown : EnumVal<"unknown", 2, 0> { let isDefault = 1; }
-def OMPC_NumTasks : Clause<"num_tasks"> {
+def OMPC_NumTasks : Clause<[Spelling<"num_tasks">]> {
   let clangClass = "OMPNumTasksClause";
   let flangClass = "OmpNumTasksClause";
   let enumClauseValue = "NumTasksType";
@@ -348,27 +350,27 @@ def OMPC_NumTasks : Clause<"num_tasks"> {
     OMP_NUMTASKS_Unknown
   ];
 }
-def OMPC_NumTeams : Clause<"num_teams"> {
+def OMPC_NumTeams : Clause<[Spelling<"num_teams">]> {
   let clangClass = "OMPNumTeamsClause";
   let flangClass = "ScalarIntExpr";
 }
-def OMPC_NumThreads : Clause<"num_threads"> {
+def OMPC_NumThreads : Clause<[Spelling<"num_threads">]> {
   let clangClass = "OMPNumThreadsClause";
   let flangClass = "ScalarIntExpr";
 }
-def OMPC_OMPX_Attribute : Clause<"ompx_attribute"> {
+def OMPC_OMPX_Attribute : Clause<[Spelling<"ompx_attribute">]> {
   let clangClass = "OMPXAttributeClause";
 }
-def OMPC_OMPX_Bare : Clause<"ompx_bare"> {
+def OMPC_OMPX_Bare : Clause<[Spelling<"ompx_bare">]> {
   let clangClass = "OMPXBareClause";
 }
-def OMPC_OMPX_DynCGroupMem : Clause<"ompx_dyn_cgroup_mem"> {
+def OMPC_OMPX_DynCGroupMem : Clause<[Spelling<"ompx_dyn_cgroup_mem">]> {
   let clangClass = "OMPXDynCGroupMemClause";
   let flangClass = "ScalarIntExpr";
 }
 def OMP_ORDER_concurrent : EnumVal<"concurrent",1,1> {}
 def OMP_ORDER_unknown : EnumVal<"unknown",2,0> { let isDefault = 1; }
-def OMPC_Order : Clause<"order"> {
+def OMPC_Order : Clause<[Spelling<"order">]> {
   let clangClass = "OMPOrderClause";
   let flangClass = "OmpOrderClause";
   let enumClauseValue = "OrderKind";
@@ -377,30 +379,30 @@ def OMPC_Order : Clause<"order"> {
     OMP_ORDER_concurrent
   ];
 }
-def OMPC_Ordered : Clause<"ordered"> {
+def OMPC_Ordered : Clause<[Spelling<"ordered">]> {
   let clangClass = "OMPOrderedClause";
   let flangClass = "ScalarIntConstantExpr";
   let isValueOptional = true;
 }
-def OMPC_Otherwise : Clause<"otherwise"> {
+def OMPC_Otherwise : Clause<[Spelling<"otherwise">]> {
   let flangClass = "OmpOtherwiseClause";
   let isValueOptional = true;
 }
-def OMPC_Partial: Clause<"partial"> {
+def OMPC_Partial: Clause<[Spelling<"partial">]> {
   let clangClass = "OMPPartialClause";
   let flangClass = "ScalarIntConstantExpr";
   let isValueOptional = true;
 }
-def OMPC_Permutation: Clause<"permutation"> {
+def OMPC_Permutation: Clause<[Spelling<"permutation">]> {
   let clangClass = "OMPPermutationClause";
   let flangClass = "ScalarIntExpr";
   let isValueList = true;
 }
-def OMPC_Priority : Clause<"priority"> {
+def OMPC_Priority : Clause<[Spelling<"priority">]> {
   let clangClass = "OMPPriorityClause";
   let flangClass = "ScalarIntExpr";
 }
-def OMPC_Private : Clause<"private"> {
+def OMPC_Private : Clause<[Spelling<"private">]> {
   let clangClass = "OMPPrivateClause";
   let flangClass = "OmpObjectList";
 }
@@ -410,7 +412,7 @@ def OMP_PROC_BIND_spread : EnumVal<"spread",4,1> {}
 def OMP_PROC_BIND_primary : EnumVal<"primary",5,1> {}
 def OMP_PROC_BIND_default : EnumVal<"default",6,0> {}
 def OMP_PROC_BIND_unknown : EnumVal<"unknown",7,0> { let isDefault = true; }
-def OMPC_ProcBind : Clause<"proc_bind"> {
+def OMPC_ProcBind : Clause<[Spelling<"proc_bind">]> {
   let clangClass = "OMPProcBindClause";
   let flangClass = "OmpProcBindClause";
   let enumClauseValue = "ProcBindKind";
@@ -423,23 +425,23 @@ def OMPC_ProcBind : Clause<"proc_bind"> {
     OMP_PROC_BIND_unknown
   ];
 }
-def OMPC_Read : Clause<"read"> {
+def OMPC_Read : Clause<[Spelling<"read">]> {
   let clangClass = "OMPReadClause";
 }
-def OMPC_Reduction : Clause<"reduction"> {
+def OMPC_Reduction : Clause<[Spelling<"reduction">]> {
   let clangClass = "OMPReductionClause";
   let flangClass = "OmpReductionClause";
 }
-def OMPC_Relaxed : Clause<"relaxed"> {
+def OMPC_Relaxed : Clause<[Spelling<"relaxed">]> {
   let clangClass = "OMPRelaxedClause";
 }
-def OMPC_Release : Clause<"release"> {
+def OMPC_Release : Clause<[Spelling<"release">]> {
   let clangClass = "OMPReleaseClause";
 }
-def OMPC_ReverseOffload : Clause<"reverse_offload"> {
+def OMPC_ReverseOffload : Clause<[Spelling<"reverse_offload">]> {
   let clangClass = "OMPReverseOffloadClause";
 }
-def OMPC_SafeLen : Clause<"safelen"> {
+def OMPC_SafeLen : Clause<[Spelling<"safelen">]> {
   let clangClass = "OMPSafelenClause";
   let flangClass = "ScalarIntConstantExpr";
 }
@@ -449,7 +451,7 @@ def OMP_SCHEDULE_Guided : EnumVal<"guided", 4, 1> {}
 def OMP_SCHEDULE_Auto : EnumVal<"auto", 5, 1> {}
 def OMP_SCHEDULE_Runtime : EnumVal<"runtime", 6, 1> {}
 def OMP_SCHEDULE_Default : EnumVal<"default", 7, 0> { let isDefault = 1; }
-def OMPC_Schedule : Clause<"schedule"> {
+def OMPC_Schedule : Clause<[Spelling<"schedule">]> {
   let clangClass = "OMPScheduleClause";
   let flangClass = "OmpScheduleClause";
   let enumClauseValue = "ScheduleKind";
@@ -462,94 +464,94 @@ def OMPC_Schedule : Clause<"schedule"> {
     OMP_SCHEDULE_Default
   ];
 }
-def OMPC_SeqCst : Clause<"seq_cst"> {
+def OMPC_SeqCst : Clause<[Spelling<"seq_cst">]> {
   let clangClass = "OMPSeqCstClause";
 }
-def OMPC_Severity : Clause<"severity"> {
+def OMPC_Severity : Clause<[Spelling<"severity">]> {
   let clangClass = "OMPSeverityClause";
   let flangClass = "OmpSeverityClause";
 }
-def OMPC_Shared : Clause<"shared"> {
+def OMPC_Shared : Clause<[Spelling<"shared">]> {
   let clangClass = "OMPSharedClause";
   let flangClass = "OmpObjectList";
 }
-def OMPC_Simd : Clause<"simd"> {
+def OMPC_Simd : Clause<[Spelling<"simd">]> {
   let clangClass = "OMPSIMDClause";
 }
-def OMPC_SimdLen : Clause<"simdlen"> {
+def OMPC_SimdLen : Clause<[Spelling<"simdlen">]> {
   let clangClass = "OMPSimdlenClause";
   let flangClass = "ScalarIntConstantExpr";
 }
-def OMPC_Sizes: Clause<"sizes"> {
+def OMPC_Sizes: Clause<[Spelling<"sizes">]> {
   let clangClass = "OMPSizesClause";
   let flangClass = "ScalarIntExpr";
   let isValueList = true;
 }
-def OMPC_TaskReduction : Clause<"task_reduction"> {
+def OMPC_TaskReduction : Clause<[Spelling<"task_reduction">]> {
   let clangClass = "OMPTaskReductionClause";
   let flangClass = "OmpTaskReductionClause";
 }
-def OMPC_ThreadLimit : Clause<"thread_limit"> {
+def OMPC_ThreadLimit : Clause<[Spelling<"thread_limit">]> {
   let clangClass = "OMPThreadLimitClause";
   let flangClass = "ScalarIntExpr";
 }
-def OMPC_ThreadPrivate : Clause<"threadprivate"> {
+def OMPC_ThreadPrivate : Clause<[Spelling<"threadprivate">]> {
   let isImplicit = true;
 }
-def OMPC_Threads : Clause<"threads"> {
+def OMPC_Threads : Clause<[Spelling<"threads">]> {
   let clangClass = "OMPThreadsClause";
 }
-def OMPC_To : Clause<"to"> {
+def OMPC_To : Clause<[Spelling<"to">]> {
   let clangClass = "OMPToClause";
   let flangClass = "OmpToClause";
 }
-def OMPC_UnifiedAddress : Clause<"unified_address"> {
+def OMPC_UnifiedAddress : Clause<[Spelling<"unified_address">]> {
   let clangClass = "OMPUnifiedAddressClause";
 }
-def OMPC_UnifiedSharedMemory : Clause<"unified_shared_memory"> {
+def OMPC_UnifiedSharedMemory : Clause<[Spelling<"unified_shared_memory">]> {
   let clangClass = "OMPUnifiedSharedMemoryClause";
 }
-def OMPC_SelfMaps : Clause<"self_maps"> {
+def OMPC_SelfMaps : Clause<[Spelling<"self_maps">]> {
   let clangClass = "OMPSelfMapsClause";
 }
-def OMPC_Uniform : Clause<"uniform"> {
+def OMPC_Uniform : Clause<[Spelling<"uniform">]> {
   let flangClass = "Name";
   let isValueList = true;
 }
-def OMPC_Unknown : Clause<"unknown"> {
+def OMPC_Unknown : Clause<[Spelling<"unknown">]> {
   let isImplicit = true;
   let isDefault = true;
 }
-def OMPC_Untied : Clause<"untied"> {
+def OMPC_Untied : Clause<[Spelling<"untied">]> {
   let clangClass = "OMPUntiedClause";
 }
-def OMPC_Update : Clause<"update"> {
+def OMPC_Update : Clause<[Spelling<"update">]> {
   let clangClass = "OMPUpdateClause";
   let flangClass = "OmpUpdateClause";
   let isValueOptional = true;
 }
-def OMPC_Use : Clause<"use"> {
+def OMPC_Use : Clause<[Spelling<"use">]> {
   let clangClass = "OMPUseClause";
   let flangClass = "OmpUseClause";
 }
-def OMPC_UsesAllocators : Clause<"uses_allocators"> {
+def OMPC_UsesAllocators : Clause<[Spelling<"uses_allocators">]> {
   let clangClass = "OMPUsesAllocatorsClause";
 }
-def OMPC_UseDeviceAddr : Clause<"use_device_addr"> {
+def OMPC_UseDeviceAddr : Clause<[Spelling<"use_device_addr">]> {
   let clangClass = "OMPUseDeviceAddrClause";
   let flangClass = "OmpObjectList";
 }
-def OMPC_UseDevicePtr : Clause<"use_device_ptr"> {
+def OMPC_UseDevicePtr : Clause<[Spelling<"use_device_ptr">]> {
   let clangClass = "OMPUseDevicePtrClause";
   let flangClass = "OmpObjectList";
 }
-def OMPC_Weak : Clause<"weak"> {
+def OMPC_Weak : Clause<[Spelling<"weak">]> {
   let clangClass = "OMPWeakClause";
 }
-def OMPC_When: Clause<"when"> {
+def OMPC_When: Clause<[Spelling<"when">]> {
   let flangClass = "OmpWhenClause";
 }
-def OMPC_Write : Clause<"write"> {
+def OMPC_Write : Clause<[Spelling<"write">]> {
   let clangClass = "OMPWriteClause";
 }
 
@@ -559,7 +561,7 @@ def OMPC_Write : Clause<"write"> {
 // follows "xyz".
 //===----------------------------------------------------------------------===//
 
-def OMP_Allocate : Directive<"allocate"> {
+def OMP_Allocate : Directive<[Spelling<"allocate">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_Align, 51>,
     VersionedClause<OMPC_Allocator>,
@@ -567,7 +569,7 @@ def OMP_Allocate : Directive<"allocate"> {
   let association = AS_None;
   let category = CA_Declarative;
 }
-def OMP_Allocators : Directive<"allocators"> {
+def OMP_Allocators : Directive<[Spelling<"allocators">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
   ];
@@ -575,7 +577,7 @@ def OMP_Allocators : Directive<"allocators"> {
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_Assumes : Directive<"assumes"> {
+def OMP_Assumes : Directive<[Spelling<"assumes">]> {
   let association = AS_None;
   let category = CA_Informational;
   let allowedOnceClauses = [
@@ -587,7 +589,7 @@ def OMP_Assumes : Directive<"assumes"> {
     VersionedClause<OMPC_NoParallelism, 51>,
   ];
 }
-def OMP_Assume : Directive<"assume"> {
+def OMP_Assume : Directive<[Spelling<"assume">]> {
   let association = AS_Block;
   let category = CA_Informational;
   let allowedOnceClauses = [
@@ -600,7 +602,7 @@ def OMP_Assume : Directive<"assume"> {
     VersionedClause<OMPC_NoOpenMPConstructs, 60>,
   ];
 }
-def OMP_Atomic : Directive<"atomic"> {
+def OMP_Atomic : Directive<[Spelling<"atomic">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_AcqRel, 50>,
     VersionedClause<OMPC_Acquire, 50>,
@@ -619,11 +621,11 @@ def OMP_Atomic : Directive<"atomic"> {
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_Barrier : Directive<"barrier"> {
+def OMP_Barrier : Directive<[Spelling<"barrier">]> {
   let association = AS_None;
   let category = CA_Executable;
 }
-def OMP_BeginAssumes : Directive<"begin assumes"> {
+def OMP_BeginAssumes : Directive<[Spelling<"begin assumes">]> {
   let association = AS_Delimited;
   let category = CA_Informational;
   let allowedOnceClauses = [
@@ -636,12 +638,12 @@ def OMP_BeginAssumes : Directive<"begin assumes"> {
   ];
   let languages = [L_C];
 }
-def OMP_EndAssumes : Directive<"end assumes"> {
+def OMP_EndAssumes : Directive<[Spelling<"end assumes">]> {
   let association = AS_Delimited;
   let category = OMP_BeginAssumes.category;
   let languages = OMP_BeginAssumes.languages;
 }
-def OMP_BeginDeclareTarget : Directive<"begin declare target"> {
+def OMP_BeginDeclareTarget : Directive<[Spelling<"begin declare target">]> {
   let allowedClauses = [
     VersionedClause<OMPC_DeviceType>,
     VersionedClause<OMPC_Indirect>,
@@ -652,22 +654,22 @@ def OMP_BeginDeclareTarget : Directive<"begin declare target"> {
   let category = CA_Declarative;
   let languages = [L_C];
 }
-def OMP_EndDeclareTarget : Directive<"end declare target"> {
+def OMP_EndDeclareTarget : Directive<[Spelling<"end declare target">]> {
   let association = AS_Delimited;
   let category = OMP_BeginDeclareTarget.category;
   let languages = OMP_BeginDeclareTarget.languages;
 }
-def OMP_BeginDeclareVariant : Directive<"begin declare variant"> {
+def OMP_BeginDeclareVariant : Directive<[Spelling<"begin declare variant">]> {
   let association = AS_Delimited;
   let category = CA_Declarative;
   let languages = [L_C];
 }
-def OMP_EndDeclareVariant : Directive<"end declare variant"> {
+def OMP_EndDeclareVariant : Directive<[Spelling<"end declare variant">]> {
   let association = AS_Delimited;
   let category = OMP_BeginDeclareVariant.category;
   let languages = OMP_BeginDeclareVariant.languages;
 }
-def OMP_Cancel : Directive<"cancel"> {
+def OMP_Cancel : Directive<[Spelling<"cancel">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_CancellationConstructType>,
     VersionedClause<OMPC_If>,
@@ -675,35 +677,35 @@ def OMP_Cancel : Directive<"cancel"> {
   let association = AS_None;
   let category = CA_Executable;
 }
-def OMP_CancellationPoint : Directive<"cancellation point"> {
+def OMP_CancellationPoint : Directive<[Spelling<"cancellation point">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_CancellationConstructType>,
   ];
   let association = AS_None;
   let category = CA_Executable;
 }
-def OMP_Critical : Directive<"critical"> {
+def OMP_Critical : Directive<[Spelling<"critical">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_Hint>,
   ];
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_DeclareMapper : Directive<"declare mapper"> {
+def OMP_DeclareMapper : Directive<[Spelling<"declare mapper">]> {
   let requiredClauses = [
     VersionedClause<OMPC_Map, 45>,
   ];
   let association = AS_None;
   let category = CA_Declarative;
 }
-def OMP_DeclareReduction : Directive<"declare reduction"> {
+def OMP_DeclareReduction : Directive<[Spelling<"declare reduction">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_Initializer>,
   ];
   let association = AS_None;
   let category = CA_Declarative;
 }
-def OMP_DeclareSimd : Directive<"declare simd"> {
+def OMP_DeclareSimd : Directive<[Spelling<"declare simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Linear>,
@@ -719,7 +721,7 @@ def OMP_DeclareSimd : Directive<"declare simd"> {
   let association = AS_Declaration;
   let category = CA_Declarative;
 }
-def OMP_DeclareTarget : Directive<"declare target"> {
+def OMP_DeclareTarget : Directive<[Spelling<"declare target">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Enter, 52>,
     VersionedClause<OMPC_Indirect>,
@@ -732,7 +734,7 @@ def OMP_DeclareTarget : Directive<"declare target"> {
   let association = AS_None;
   let category = CA_Declarative;
 }
-def OMP_DeclareVariant : Directive<"declare variant"> {
+def OMP_DeclareVariant : Directive<[Spelling<"declare variant">]> {
   let allowedClauses = [
     VersionedClause<OMPC_AdjustArgs, 51>,
   ];
@@ -744,7 +746,7 @@ def OMP_DeclareVariant : Directive<"declare variant"> {
   let category = CA_Declarative;
   let languages = [L_C];
 }
-def OMP_Depobj : Directive<"depobj"> {
+def OMP_Depobj : Directive<[Spelling<"depobj">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Depend, 50>,
     // TODO This should ne `none` instead. Comment carried over from
@@ -756,7 +758,7 @@ def OMP_Depobj : Directive<"depobj"> {
   let association = AS_None;
   let category = CA_Executable;
 }
-def OMP_dispatch : Directive<"dispatch"> {
+def OMP_dispatch : Directive<[Spelling<"dispatch">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Depend>,
     VersionedClause<OMPC_Device>,
@@ -769,7 +771,7 @@ def OMP_dispatch : Directive<"dispatch"> {
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_Distribute : Directive<"distribute"> {
+def OMP_Distribute : Directive<[Spelling<"distribute">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_FirstPrivate>,
@@ -784,7 +786,7 @@ def OMP_Distribute : Directive<"distribute"> {
   let association = AS_Loop;
   let category = CA_Executable;
 }
-def OMP_Do : Directive<"do"> {
+def OMP_Do : Directive<[Spelling<"do">]> {
   let allowedClauses = [
     VersionedClause<OMPC_FirstPrivate>,
     VersionedClause<OMPC_LastPrivate>,
@@ -803,7 +805,7 @@ def OMP_Do : Directive<"do"> {
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_EndDo : Directive<"end do"> {
+def OMP_EndDo : Directive<[Spelling<"end do">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_NoWait>,
   ];
@@ -812,7 +814,7 @@ def OMP_EndDo : Directive<"end do"> {
   let category = OMP_Do.category;
   let languages = OMP_Do.languages;
 }
-def OMP_Error : Directive<"error"> {
+def OMP_Error : Directive<[Spelling<"error">]> {
   let allowedClauses = [
     VersionedClause<OMPC_At, 51>,
     VersionedClause<OMPC_Message, 51>,
@@ -821,7 +823,7 @@ def OMP_Error : Directive<"error"> {
   let association = AS_None;
   let category = CA_Utility;
 }
-def OMP_Flush : Directive<"flush"> {
+def OMP_Flush : Directive<[Spelling<"flush">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_AcqRel, 50>,
     VersionedClause<OMPC_Acquire, 50>,
@@ -834,7 +836,7 @@ def OMP_Flush : Directive<"flush"> {
   let association = AS_None;
   let category = CA_Executable;
 }
-def OMP_For : Directive<"for"> {
+def OMP_For : Directive<[Spelling<"for">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Collapse>,
@@ -852,14 +854,14 @@ def OMP_For : Directive<"for"> {
   let category = CA_Executable;
   let languages = [L_C];
 }
-def OMP_Interchange : Directive<"interchange"> {
+def OMP_Interchange : Directive<[Spelling<"interchange">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_Permutation>,
   ];
   let association = AS_Loop;
   let category = CA_Executable;
 }
-def OMP_interop : Directive<"interop"> {
+def OMP_interop : Directive<[Spelling<"interop">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Depend>,
     VersionedClause<OMPC_Destroy>,
@@ -871,7 +873,7 @@ def OMP_interop : Directive<"interop"> {
   let association = AS_None;
   let category = CA_Executable;
 }
-def OMP_loop : Directive<"loop"> {
+def OMP_loop : Directive<[Spelling<"loop">]> {
   let allowedClauses = [
     VersionedClause<OMPC_LastPrivate>,
     VersionedClause<OMPC_Private>,
@@ -885,18 +887,18 @@ def OMP_loop : Directive<"loop"> {
   let association = AS_Loop;
   let category = CA_Executable;
 }
-def OMP_masked : Directive<"masked"> {
+def OMP_masked : Directive<[Spelling<"masked">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_Filter>,
   ];
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_Master : Directive<"master"> {
+def OMP_Master : Directive<[Spelling<"master">]> {
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_Metadirective : Directive<"metadirective"> {
+def OMP_Metadirective : Directive<[Spelling<"metadirective">]> {
   let allowedClauses = [
     VersionedClause<OMPC_When>,
   ];
@@ -907,11 +909,11 @@ def OMP_Metadirective : Directive<"metadirective"> {
   let association = AS_None;
   let category = CA_Meta;
 }
-def OMP_Nothing : Directive<"nothing"> {
+def OMP_Nothing : Directive<[Spelling<"nothing">]> {
   let association = AS_None;
   let category = CA_Utility;
 }
-def OMP_Ordered : Directive<"ordered"> {
+def OMP_Ordered : Directive<[Spelling<"ordered">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Depend>,
     VersionedClause<OMPC_Doacross, 52>,
@@ -924,7 +926,7 @@ def OMP_Ordered : Directive<"ordered"> {
   // There is also a block-associated "ordered" directive.
   let category = CA_Executable;
 }
-def OMP_Parallel : Directive<"parallel"> {
+def OMP_Parallel : Directive<[Spelling<"parallel">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Copyin>,
@@ -943,7 +945,7 @@ def OMP_Parallel : Directive<"parallel"> {
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_Requires : Directive<"requires"> {
+def OMP_Requires : Directive<[Spelling<"requires">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_UnifiedAddress>,
     VersionedClause<OMPC_UnifiedSharedMemory>,
@@ -962,11 +964,11 @@ def OMP_Requires : Directive<"requires"> {
   let association = AS_None;
   let category = CA_Informational;
 }
-def OMP_Reverse : Directive<"reverse"> {
+def OMP_Reverse : Directive<[Spelling<"reverse">]> {
   let association = AS_Loop;
   let category = CA_Executable;
 }
-def OMP_Scan : Directive<"scan"> {
+def OMP_Scan : Directive<[Spelling<"scan">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Exclusive>,
     VersionedClause<OMPC_Inclusive>,
@@ -974,7 +976,7 @@ def OMP_Scan : Directive<"scan"> {
   let association = AS_Separating;
   let category = CA_Subsidiary;
 }
-def OMP_Scope : Directive<"scope"> {
+def OMP_Scope : Directive<[Spelling<"scope">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Private, 51>,
     VersionedClause<OMPC_Reduction, 51>,
@@ -987,7 +989,7 @@ def OMP_Scope : Directive<"scope"> {
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_EndScope : Directive<"end scope"> {
+def OMP_EndScope : Directive<[Spelling<"end scope">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_NoWait>,
   ];
@@ -996,11 +998,11 @@ def OMP_EndScope : Directive<"end scope"> {
   let category = OMP_Scope.category;
   let languages = [L_Fortran];
 }
-def OMP_Section : Directive<"section"> {
+def OMP_Section : Directive<[Spelling<"section">]> {
   let association = AS_Separating;
   let category = CA_Subsidiary;
 }
-def OMP_Sections : Directive<"sections"> {
+def OMP_Sections : Directive<[Spelling<"sections">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_FirstPrivate>,
@@ -1012,7 +1014,7 @@ def OMP_Sections : Directive<"sections"> {
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_EndSections : Directive<"end sections"> {
+def OMP_EndSections : Directive<[Spelling<"end sections">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_NoWait>,
   ];
@@ -1021,7 +1023,7 @@ def OMP_EndSections : Directive<"end sections"> {
   let category = OMP_Sections.category;
   let languages = [L_Fortran];
 }
-def OMP_Simd : Directive<"simd"> {
+def OMP_Simd : Directive<[Spelling<"simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -1041,7 +1043,7 @@ def OMP_Simd : Directive<"simd"> {
   let association = AS_Loop;
   let category = CA_Executable;
 }
-def OMP_Single : Directive<"single"> {
+def OMP_Single : Directive<[Spelling<"single">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_CopyPrivate>,
@@ -1054,7 +1056,7 @@ def OMP_Single : Directive<"single"> {
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_EndSingle : Directive<"end single"> {
+def OMP_EndSingle : Directive<[Spelling<"end single">]> {
   let allowedClauses = [
     VersionedClause<OMPC_CopyPrivate>,
   ];
@@ -1066,7 +1068,7 @@ def OMP_EndSingle : Directive<"end single"> {
   let category = OMP_Single.category;
   let languages = [L_Fortran];
 }
-def OMP_Target : Directive<"target"> {
+def OMP_Target : Directive<[Spelling<"target">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Depend>,
@@ -1091,7 +1093,7 @@ def OMP_Target : Directive<"target"> {
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_TargetData : Directive<"target data"> {
+def OMP_TargetData : Directive<[Spelling<"target data">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_Device>,
     VersionedClause<OMPC_If>,
@@ -1104,7 +1106,7 @@ def OMP_TargetData : Directive<"target data"> {
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_TargetEnterData : Directive<"target enter data"> {
+def OMP_TargetEnterData : Directive<[Spelling<"target enter data">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Depend>,
   ];
@@ -1119,7 +1121,7 @@ def OMP_TargetEnterData : Directive<"target enter data"> {
   let association = AS_None;
   let category = CA_Executable;
 }
-def OMP_TargetExitData : Directive<"target exit data"> {
+def OMP_TargetExitData : Directive<[Spelling<"target exit data">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Depend>,
   ];
@@ -1134,7 +1136,7 @@ def OMP_TargetExitData : Directive<"target exit data"> {
   let association = AS_None;
   let category = CA_Executable;
 }
-def OMP_TargetUpdate : Directive<"target update"> {
+def OMP_TargetUpdate : Directive<[Spelling<"target update">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Depend>,
     VersionedClause<OMPC_From>,
@@ -1148,7 +1150,7 @@ def OMP_TargetUpdate : Directive<"target update"> {
   let association = AS_None;
   let category = CA_Executable;
 }
-def OMP_Task : Directive<"task"> {
+def OMP_Task : Directive<[Spelling<"task">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Affinity, 50>,
     VersionedClause<OMPC_Allocate>,
@@ -1170,7 +1172,7 @@ def OMP_Task : Directive<"task"> {
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_TaskGroup : Directive<"taskgroup"> {
+def OMP_TaskGroup : Directive<[Spelling<"taskgroup">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate, 50>,
     VersionedClause<OMPC_TaskReduction, 50>,
@@ -1178,7 +1180,7 @@ def OMP_TaskGroup : Directive<"taskgroup"> {
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_TaskLoop : Directive<"taskloop"> {
+def OMP_TaskLoop : Directive<[Spelling<"taskloop">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_FirstPrivate>,
@@ -1205,7 +1207,7 @@ def OMP_TaskLoop : Directive<"taskloop"> {
   let association = AS_Loop;
   let category = CA_Executable;
 }
-def OMP_TaskWait : Directive<"taskwait"> {
+def OMP_TaskWait : Directive<[Spelling<"taskwait">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Depend, 50>,
     VersionedClause<OMPC_NoWait, 51>,
@@ -1213,11 +1215,11 @@ def OMP_TaskWait : Directive<"taskwait"> {
   let association = AS_None;
   let category = CA_Executable;
 }
-def OMP_TaskYield : Directive<"taskyield"> {
+def OMP_TaskYield : Directive<[Spelling<"taskyield">]> {
   let association = AS_None;
   let category = CA_Executable;
 }
-def OMP_Teams : Directive<"teams"> {
+def OMP_Teams : Directive<[Spelling<"teams">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_FirstPrivate>,
@@ -1235,30 +1237,30 @@ def OMP_Teams : Directive<"teams"> {
   let association = AS_Block;
   let category = CA_Executable;
 }
-def OMP_ThreadPrivate : Directive<"threadprivate"> {
+def OMP_ThreadPrivate : Directive<[Spelling<"threadprivate">]> {
   let association = AS_None;
   let category = CA_Declarative;
 }
-def OMP_Tile : Directive<"tile"> {
+def OMP_Tile : Directive<[Spelling<"tile">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_Sizes, 51>,
   ];
   let association = AS_Loop;
   let category = CA_Executable;
 }
-def OMP_Stripe : Directive<"stripe"> {
+def OMP_Stripe : Directive<[Spelling<"stripe">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_Sizes, 60>,
   ];
   let association = AS_Loop;
   let category = CA_Executable;
 }
-def OMP_Unknown : Directive<"unknown"> {
+def OMP_Unknown : Directive<[Spelling<"unknown">]> {
   let isDefault = true;
   let association = AS_None;
   let category = CA_Utility;
 }
-def OMP_Unroll : Directive<"unroll"> {
+def OMP_Unroll : Directive<[Spelling<"unroll">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_Full, 51>,
     VersionedClause<OMPC_Partial, 51>,
@@ -1266,7 +1268,7 @@ def OMP_Unroll : Directive<"unroll"> {
   let association = AS_Loop;
   let category = CA_Executable;
 }
-def OMP_Workshare : Directive<"workshare"> {
+def OMP_Workshare : Directive<[Spelling<"workshare">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_NoWait>,
   ];
@@ -1274,7 +1276,7 @@ def OMP_Workshare : Directive<"workshare"> {
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_EndWorkshare : Directive<"end workshare"> {
+def OMP_EndWorkshare : Directive<[Spelling<"end workshare">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_NoWait>,
   ];
@@ -1290,7 +1292,7 @@ def OMP_EndWorkshare : Directive<"end workshare"> {
 // follows "xyz".
 //===----------------------------------------------------------------------===//
 
-def OMP_DistributeParallelDo : Directive<"distribute parallel do"> {
+def OMP_DistributeParallelDo : Directive<[Spelling<"distribute parallel do">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Copyin>,
@@ -1315,7 +1317,8 @@ def OMP_DistributeParallelDo : Directive<"distribute parallel do"> {
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_DistributeParallelDoSimd : Directive<"distribute parallel do simd"> {
+def OMP_DistributeParallelDoSimd
+    : Directive<[Spelling<"distribute parallel do simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -1342,7 +1345,8 @@ def OMP_DistributeParallelDoSimd : Directive<"distribute parallel do simd"> {
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_DistributeParallelFor : Directive<"distribute parallel for"> {
+def OMP_DistributeParallelFor
+    : Directive<[Spelling<"distribute parallel for">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Collapse>,
@@ -1365,7 +1369,8 @@ def OMP_DistributeParallelFor : Directive<"distribute parallel for"> {
   let category = CA_Executable;
   let languages = [L_C];
 }
-def OMP_DistributeParallelForSimd : Directive<"distribute parallel for simd"> {
+def OMP_DistributeParallelForSimd
+    : Directive<[Spelling<"distribute parallel for simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -1393,7 +1398,7 @@ def OMP_DistributeParallelForSimd : Directive<"distribute parallel for simd"> {
   let category = CA_Executable;
   let languages = [L_C];
 }
-def OMP_DistributeSimd : Directive<"distribute simd"> {
+def OMP_DistributeSimd : Directive<[Spelling<"distribute simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -1420,7 +1425,7 @@ def OMP_DistributeSimd : Directive<"distribute simd"> {
   let leafConstructs = [OMP_Distribute, OMP_Simd];
   let category = CA_Executable;
 }
-def OMP_DoSimd : Directive<"do simd"> {
+def OMP_DoSimd : Directive<[Spelling<"do simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_FirstPrivate>,
@@ -1443,7 +1448,7 @@ def OMP_DoSimd : Directive<"do simd"> {
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_EndDoSimd : Directive<"end do simd"> {
+def OMP_EndDoSimd : Directive<[Spelling<"end do simd">]> {
   let allowedOnceClauses = [
     VersionedClause<OMPC_NoWait>,
   ];
@@ -1452,7 +1457,7 @@ def OMP_EndDoSimd : Directive<"end do simd"> {
   let category = OMP_DoSimd.category;
   let languages = [L_Fortran];
 }
-def OMP_ForSimd : Directive<"for simd"> {
+def OMP_ForSimd : Directive<[Spelling<"for simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -1474,7 +1479,7 @@ def OMP_ForSimd : Directive<"for simd"> {
   let leafConstructs = [OMP_For, OMP_Simd];
   let category = CA_Executable;
 }
-def OMP_target_loop : Directive<"target loop"> {
+def OMP_target_loop : Directive<[Spelling<"target loop">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Depend>,
@@ -1504,7 +1509,7 @@ def OMP_target_loop : Directive<"target loop"> {
   let leafConstructs = [OMP_Target, OMP_loop];
   let category = CA_Executable;
 }
-def OMP_MaskedTaskloop : Directive<"masked taskloop"> {
+def OMP_MaskedTaskloop : Directive<[Spelling<"masked taskloop">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Collapse>,
@@ -1528,7 +1533,7 @@ def OMP_MaskedTaskloop : Directive<"masked taskloop"> {
   let leafConstructs = [OMP_masked, OMP_TaskLoop];
   let category = CA_Executable;
 }
-def OMP_MaskedTaskloopSimd : Directive<"masked taskloop simd"> {
+def OMP_MaskedTaskloopSimd : Directive<[Spelling<"masked taskloop simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -1558,7 +1563,7 @@ def OMP_MaskedTaskloopSimd : Directive<"masked taskloop simd"> {
   let leafConstructs = [OMP_masked, OMP_TaskLoop, OMP_Simd];
   let category = CA_Executable;
 }
-def OMP_MasterTaskloop : Directive<"master taskloop"> {
+def OMP_MasterTaskloop : Directive<[Spelling<"master taskloop">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Collapse>,
@@ -1581,7 +1586,7 @@ def OMP_MasterTaskloop : Directive<"master taskloop"> {
   let leafConstructs = [OMP_Master, OMP_TaskLoop];
   let category = CA_Executable;
 }
-def OMP_MasterTaskloopSimd : Directive<"master taskloop simd"> {
+def OMP_MasterTaskloopSimd : Directive<[Spelling<"master taskloop simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -1610,7 +1615,7 @@ def OMP_MasterTaskloopSimd : Directive<"master taskloop simd"> {
   let leafConstructs = [OMP_Master, OMP_TaskLoop, OMP_Simd];
   let category = CA_Executable;
 }
-def OMP_ParallelDo : Directive<"parallel do"> {
+def OMP_ParallelDo : Directive<[Spelling<"parallel do">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Copyin>,
     VersionedClause<OMPC_Default>,
@@ -1634,7 +1639,7 @@ def OMP_ParallelDo : Directive<"parallel do"> {
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_ParallelDoSimd : Directive<"parallel do simd"> {
+def OMP_ParallelDoSimd : Directive<[Spelling<"parallel do simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -1663,7 +1668,7 @@ def OMP_ParallelDoSimd : Directive<"parallel do simd"> {
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_ParallelFor : Directive<"parallel for"> {
+def OMP_ParallelFor : Directive<[Spelling<"parallel for">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Collapse>,
@@ -1687,7 +1692,7 @@ def OMP_ParallelFor : Directive<"parallel for"> {
   let category = CA_Executable;
   let languages = [L_C];
 }
-def OMP_ParallelForSimd : Directive<"parallel for simd"> {
+def OMP_ParallelForSimd : Directive<[Spelling<"parallel for simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -1715,7 +1720,7 @@ def OMP_ParallelForSimd : Directive<"parallel for simd"> {
   let category = CA_Executable;
   let languages = [L_C];
 }
-def OMP_parallel_loop : Directive<"parallel loop"> {
+def OMP_parallel_loop : Directive<[Spelling<"parallel loop">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Copyin>,
@@ -1738,7 +1743,7 @@ def OMP_parallel_loop : Directive<"parallel loop"> {
   let leafConstructs = [OMP_Parallel, OMP_loop];
   let category = CA_Executable;
 }
-def OMP_ParallelMasked : Directive<"parallel masked"> {
+def OMP_ParallelMasked : Directive<[Spelling<"parallel masked">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Copyin>,
@@ -1756,8 +1761,8 @@ def OMP_ParallelMasked : Directive<"parallel masked"> {
   let leafConstructs = [OMP_Parallel, OMP_masked];
   let category = CA_Executable;
 }
-def OMP_ParallelMaskedTaskloop :
-    Directive<"parallel masked taskloop"> {
+def OMP_ParallelMaskedTaskloop
+    : Directive<[Spelling<"parallel masked taskloop">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Collapse>,
@@ -1784,8 +1789,8 @@ def OMP_ParallelMaskedTaskloop :
   let leafConstructs = [OMP_Parallel, OMP_masked, OMP_TaskLoop];
   let category = CA_Executable;
 }
-def OMP_ParallelMaskedTaskloopSimd :
-    Directive<"parallel masked taskloop simd"> {
+def OMP_ParallelMaskedTaskloopSimd
+    : Directive<[Spelling<"parallel masked taskloop simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -1818,7 +1823,7 @@ def OMP_ParallelMaskedTaskloopSimd :
   let leafConstructs = [OMP_Parallel, OMP_masked, OMP_TaskLoop, OMP_Simd];
   let category = CA_Executable;
 }
-def OMP_ParallelMaster : Directive<"parallel master"> {
+def OMP_ParallelMaster : Directive<[Spelling<"parallel master">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Copyin>,
@@ -1835,8 +1840,8 @@ def OMP_ParallelMaster : Directive<"parallel master"> {
   let leafConstructs = [OMP_Parallel, OMP_Master];
   let category = CA_Executable;
 }
-def OMP_ParallelMasterTaskloop :
-    Directive<"parallel master taskloop"> {
+def OMP_ParallelMasterTaskloop
+    : Directive<[Spelling<"parallel master taskloop">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Collapse>,
@@ -1862,8 +1867,8 @@ def OMP_ParallelMasterTaskloop :
   let leafConstructs = [OMP_Parallel, OMP_Master, OMP_TaskLoop];
   let category = CA_Executable;
 }
-def OMP_ParallelMasterTaskloopSimd :
-    Directive<"parallel master taskloop simd"> {
+def OMP_ParallelMasterTaskloopSimd
+    : Directive<[Spelling<"parallel master taskloop simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -1895,7 +1900,7 @@ def OMP_ParallelMasterTaskloopSimd :
   let leafConstructs = [OMP_Parallel, OMP_Master, OMP_TaskLoop, OMP_Simd];
   let category = CA_Executable;
 }
-def OMP_ParallelSections : Directive<"parallel sections"> {
+def OMP_ParallelSections : Directive<[Spelling<"parallel sections">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Copyin>,
@@ -1915,7 +1920,7 @@ def OMP_ParallelSections : Directive<"parallel sections"> {
   let leafConstructs = [OMP_Parallel, OMP_Sections];
   let category = CA_Executable;
 }
-def OMP_ParallelWorkshare : Directive<"parallel workshare"> {
+def OMP_ParallelWorkshare : Directive<[Spelling<"parallel workshare">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Copyin>,
@@ -1934,7 +1939,7 @@ def OMP_ParallelWorkshare : Directive<"parallel workshare"> {
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_TargetParallel : Directive<"target parallel"> {
+def OMP_TargetParallel : Directive<[Spelling<"target parallel">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Default>,
@@ -1962,7 +1967,7 @@ def OMP_TargetParallel : Directive<"target parallel"> {
   let leafConstructs = [OMP_Target, OMP_Parallel];
   let category = CA_Executable;
 }
-def OMP_TargetParallelDo : Directive<"target parallel do"> {
+def OMP_TargetParallelDo : Directive<[Spelling<"target parallel do">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocator>,
     VersionedClause<OMPC_Default>,
@@ -1994,7 +1999,8 @@ def OMP_TargetParallelDo : Directive<"target parallel do"> {
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_TargetParallelDoSimd : Directive<"target parallel do simd"> {
+def OMP_TargetParallelDoSimd
+    : Directive<[Spelling<"target parallel do simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -2028,7 +2034,7 @@ def OMP_TargetParallelDoSimd : Directive<"target parallel do simd"> {
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_TargetParallelFor : Directive<"target parallel for"> {
+def OMP_TargetParallelFor : Directive<[Spelling<"target parallel for">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Collapse>,
@@ -2063,7 +2069,8 @@ def OMP_TargetParallelFor : Directive<"target parallel for"> {
   let category = CA_Executable;
   let languages = [L_C];
 }
-def OMP_TargetParallelForSimd : Directive<"target parallel for simd"> {
+def OMP_TargetParallelForSimd
+    : Directive<[Spelling<"target parallel for simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -2102,7 +2109,7 @@ def OMP_TargetParallelForSimd : Directive<"target parallel for simd"> {
   let category = CA_Executable;
   let languages = [L_C];
 }
-def OMP_target_parallel_loop : Directive<"target parallel loop"> {
+def OMP_target_parallel_loop : Directive<[Spelling<"target parallel loop">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Depend>,
@@ -2134,7 +2141,7 @@ def OMP_target_parallel_loop : Directive<"target parallel loop"> {
   let leafConstructs = [OMP_Target, OMP_Parallel, OMP_loop];
   let category = CA_Executable;
 }
-def OMP_TargetSimd : Directive<"target simd"> {
+def OMP_TargetSimd : Directive<[Spelling<"target simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -2170,7 +2177,7 @@ def OMP_TargetSimd : Directive<"target simd"> {
   let leafConstructs = [OMP_Target, OMP_Simd];
   let category = CA_Executable;
 }
-def OMP_TargetTeams : Directive<"target teams"> {
+def OMP_TargetTeams : Directive<[Spelling<"target teams">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Depend>,
@@ -2198,7 +2205,8 @@ def OMP_TargetTeams : Directive<"target teams"> {
   let leafConstructs = [OMP_Target, OMP_Teams];
   let category = CA_Executable;
 }
-def OMP_TargetTeamsDistribute : Directive<"target teams distribute"> {
+def OMP_TargetTeamsDistribute
+    : Directive<[Spelling<"target teams distribute">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Depend>,
@@ -2229,8 +2237,8 @@ def OMP_TargetTeamsDistribute : Directive<"target teams distribute"> {
   let leafConstructs = [OMP_Target, OMP_Teams, OMP_Distribute];
   let category = CA_Executable;
 }
-def OMP_TargetTeamsDistributeParallelDo :
-    Directive<"target teams distribute parallel do"> {
+def OMP_TargetTeamsDistributeParallelDo
+    : Directive<[Spelling<"target teams distribute parallel do">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Depend>,
@@ -2265,8 +2273,8 @@ def OMP_TargetTeamsDistributeParallelDo :
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_TargetTeamsDistributeParallelDoSimd :
-    Directive<"target teams distribute parallel do simd"> {
+def OMP_TargetTeamsDistributeParallelDoSimd
+    : Directive<[Spelling<"target teams distribute parallel do simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -2305,8 +2313,8 @@ def OMP_TargetTeamsDistributeParallelDoSimd :
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_TargetTeamsDistributeParallelFor :
-    Directive<"target teams distribute parallel for"> {
+def OMP_TargetTeamsDistributeParallelFor
+    : Directive<[Spelling<"target teams distribute parallel for">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Collapse>,
@@ -2342,8 +2350,8 @@ def OMP_TargetTeamsDistributeParallelFor :
   let category = CA_Executable;
   let languages = [L_C];
 }
-def OMP_TargetTeamsDistributeParallelForSimd :
-    Directive<"target teams distribute parallel for simd"> {
+def OMP_TargetTeamsDistributeParallelForSimd
+    : Directive<[Spelling<"target teams distribute parallel for simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -2384,8 +2392,8 @@ def OMP_TargetTeamsDistributeParallelForSimd :
   let category = CA_Executable;
   let languages = [L_C];
 }
-def OMP_TargetTeamsDistributeSimd :
-    Directive<"target teams distribute simd"> {
+def OMP_TargetTeamsDistributeSimd
+    : Directive<[Spelling<"target teams distribute simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -2420,7 +2428,7 @@ def OMP_TargetTeamsDistributeSimd :
   let leafConstructs = [OMP_Target, OMP_Teams, OMP_Distribute, OMP_Simd];
   let category = CA_Executable;
 }
-def OMP_target_teams_loop : Directive<"target teams loop"> {
+def OMP_target_teams_loop : Directive<[Spelling<"target teams loop">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_DefaultMap>,
@@ -2451,7 +2459,7 @@ def OMP_target_teams_loop : Directive<"target teams loop"> {
   let leafConstructs = [OMP_Target, OMP_Teams, OMP_loop];
   let category = CA_Executable;
 }
-def OMP_TaskLoopSimd : Directive<"taskloop simd"> {
+def OMP_TaskLoopSimd : Directive<[Spelling<"taskloop simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -2484,7 +2492,7 @@ def OMP_TaskLoopSimd : Directive<"taskloop simd"> {
   let leafConstructs = [OMP_TaskLoop, OMP_Simd];
   let category = CA_Executable;
 }
-def OMP_TeamsDistribute : Directive<"teams distribute"> {
+def OMP_TeamsDistribute : Directive<[Spelling<"teams distribute">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Collapse>,
@@ -2506,8 +2514,8 @@ def OMP_TeamsDistribute : Directive<"teams distribute"> {
   let leafConstructs = [OMP_Teams, OMP_Distribute];
   let category = CA_Executable;
 }
-def OMP_TeamsDistributeParallelDo :
-    Directive<"teams distribute parallel do"> {
+def OMP_TeamsDistributeParallelDo
+    : Directive<[Spelling<"teams distribute parallel do">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Copyin>,
@@ -2534,8 +2542,8 @@ def OMP_TeamsDistributeParallelDo :
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_TeamsDistributeParallelDoSimd :
-    Directive<"teams distribute parallel do simd"> {
+def OMP_TeamsDistributeParallelDoSimd
+    : Directive<[Spelling<"teams distribute parallel do simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -2566,8 +2574,8 @@ def OMP_TeamsDistributeParallelDoSimd :
   let category = CA_Executable;
   let languages = [L_Fortran];
 }
-def OMP_TeamsDistributeParallelFor :
-    Directive<"teams distribute parallel for"> {
+def OMP_TeamsDistributeParallelFor
+    : Directive<[Spelling<"teams distribute parallel for">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_Collapse>,
@@ -2592,8 +2600,8 @@ def OMP_TeamsDistributeParallelFor :
   let category = CA_Executable;
   let languages = [L_C];
 }
-def OMP_TeamsDistributeParallelForSimd :
-    Directive<"teams distribute parallel for simd"> {
+def OMP_TeamsDistributeParallelForSimd
+    : Directive<[Spelling<"teams distribute parallel for simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -2623,7 +2631,7 @@ def OMP_TeamsDistributeParallelForSimd :
   let category = CA_Executable;
   let languages = [L_C];
 }
-def OMP_TeamsDistributeSimd : Directive<"teams distribute simd"> {
+def OMP_TeamsDistributeSimd : Directive<[Spelling<"teams distribute simd">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Aligned>,
     VersionedClause<OMPC_Allocate>,
@@ -2650,7 +2658,7 @@ def OMP_TeamsDistributeSimd : Directive<"teams distribute simd"> {
   let leafConstructs = [OMP_Teams, OMP_Distribute, OMP_Simd];
   let category = CA_Executable;
 }
-def OMP_teams_loop : Directive<"teams loop"> {
+def OMP_teams_loop : Directive<[Spelling<"teams loop">]> {
   let allowedClauses = [
     VersionedClause<OMPC_Allocate>,
     VersionedClause<OMPC_FirstPrivate>,
diff --git a/llvm/include/llvm/TableGen/DirectiveEmitter.h b/llvm/include/llvm/TableGen/DirectiveEmitter.h
index 48e18de0904c0..1235b7638e761 100644
--- a/llvm/include/llvm/TableGen/DirectiveEmitter.h
+++ b/llvm/include/llvm/TableGen/DirectiveEmitter.h
@@ -17,6 +17,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/TableGen/Record.h"
 #include <algorithm>
 #include <string>
@@ -94,6 +95,52 @@ class DirectiveLanguage {
   }
 };
 
+class Versioned {
+public:
+  int getMinVersion(const Record *R) const {
+    int64_t Min = R->getValueAsInt("minVersion");
+    assert(llvm::isInt<IntWidth>(Min) && "Value out of range of 'int'");
+    return Min;
+  }
+
+  int getMaxVersion(const Record *R) const {
+    int64_t Max = R->getValueAsInt("maxVersion");
+    assert(llvm::isInt<IntWidth>(Max) && "Value out of range of 'int'");
+    return Max;
+  }
+
+private:
+  constexpr static int IntWidth = 8 * sizeof(int);
+};
+
+// Range of specification versions: [Min, Max]
+// Default value: all possible versions.
+// This is the same structure as the one emitted into the generated sources.
+#define STRUCT_VERSION_RANGE                                                   \
+  struct VersionRange {                                                        \
+    int Min = 1;                                                               \
+    int Max = INT_MAX;                                                         \
+  }
+
+STRUCT_VERSION_RANGE;
+
+class Spelling : public Versioned {
+public:
+  using Value = std::pair<StringRef, VersionRange>;
+
+  Spelling(const Record *Def) : Def(Def) {}
+
+  StringRef getText() const { return Def->getValueAsString("spelling"); }
+  VersionRange getVersions() const {
+    return VersionRange{getMinVersion(Def), getMaxVersion(Def)};
+  }
+
+  Value get() const { return std::make_pair(getText(), getVersions()); }
+
+private:
+  const Record *Def;
+};
+
 // Note: In all the classes below, allow implicit construction from Record *,
 // to allow writing code like:
 //  for (const Directive D : getDirectives()) {
@@ -109,7 +156,33 @@ class BaseRecord {
 public:
   BaseRecord(const Record *Def) : Def(Def) {}
 
-  StringRef getName() const { return Def->getValueAsString("name"); }
+  std::vector<Spelling::Value> getSpellings() const {
+    std::vector<Spelling::Value> List;
+    llvm::transform(
+        Def->getValueAsListOfDefs("spellings"), std::back_inserter(List),
+        [](const Record *R) { return Spelling(R).get(); });
+    return List;
+  }
+
+  StringRef getSpellingForIdentifier() const {
+    // From all spellings, pick the first one with the minimum version
+    // (i.e. pick the first from all the oldest ones). This guarantees
+    // that given several equivalent (in terms of versions) names, the
+    // first one is used, e.g. given
+    //   Clause<[Spelling<"foo">, Spelling<"bar">]> ...
+    // "foo" will be the selected spelling.
+    //
+    // This is a suitable spelling for generating an identifier name,
+    // since it will remain unchanged when any potential new spellings
+    // are added.
+    Spelling::Value Oldest{"not found", {/*Min=*/INT_MAX, 0}};
+    for (auto V : getSpellings()) {
+      if (V.second.Min < Oldest.second.Min) {
+        Oldest = V;
+      }
+    }
+    return Oldest.first;
+  }
 
   // Returns the name of the directive formatted for output. Whitespace are
   // replaced with underscores.
@@ -145,7 +218,9 @@ class BaseRecord {
   }
 
   std::string getFormattedName() const {
-    return getSnakeName(Def->getValueAsString("name"));
+    if (auto maybeName = Def->getValueAsOptionalString("name"))
+      return getSnakeName(*maybeName);
+    return getSnakeName(getSpellingForIdentifier());
   }
 
   bool isDefault() const { return Def->getValueAsBit("isDefault"); }
@@ -197,7 +272,7 @@ class Directive : public BaseRecord {
 
   // Clang uses a different format for names of its directives enum.
   std::string getClangAccSpelling() const {
-    StringRef Name = Def->getValueAsString("name");
+    StringRef Name = getSpellingForIdentifier();
 
     // Clang calls the 'unknown' value 'invalid'.
     if (Name == "unknown")
@@ -229,7 +304,7 @@ class Clause : public BaseRecord {
   // ex: async -> Async
   //     num_threads -> NumThreads
   std::string getFormattedParserClassName() const {
-    StringRef Name = Def->getValueAsString("name");
+    StringRef Name = getSpellingForIdentifier();
     return BaseRecord::getUpperCamelName(Name, "_");
   }
 
@@ -241,7 +316,7 @@ class Clause : public BaseRecord {
         !ClangSpelling.empty())
       return ClangSpelling.str();
 
-    StringRef Name = Def->getValueAsString("name");
+    StringRef Name = getSpellingForIdentifier();
     return BaseRecord::getUpperCamelName(Name, "_");
   }
 
diff --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td
index f756f54c03bfb..8196a30d03df4 100644
--- a/llvm/test/TableGen/directive1.td
+++ b/llvm/test/TableGen/directive1.td
@@ -18,7 +18,7 @@ def TDLCV_vala : EnumVal<"vala",1,1> {}
 def TDLCV_valb : EnumVal<"valb",2,1> {}
 def TDLCV_valc : EnumVal<"valc",3,0> { let isDefault = 1; }
 
-def TDLC_ClauseA : Clause<"clausea"> {
+def TDLC_ClauseA : Clause<[Spelling<"clausea">]> {
   let enumClauseValue = "AKind";
   let allowedClauseValues = [
     TDLCV_vala,
@@ -27,19 +27,18 @@ def TDLC_ClauseA : Clause<"clausea"> {
   ];
 }
 
-def TDLC_ClauseB : Clause<"clauseb"> {
+def TDLC_ClauseB : Clause<[Spelling<"clauseb">]> {
   let flangClass = "IntExpr";
   let isValueOptional = 1;
   let isDefault = 1;
 }
 
-def TDLC_ClauseC : Clause<"clausec"> {
-  let aliases = ["ccccccc"];
+def TDLC_ClauseC : Clause<[Spelling<"clausec">, Spelling<"ccccccc">]> {
   let flangClass = "IntExpr";
   let isValueList = 1;
 }
 
-def TDL_DirA : Directive<"dira"> {
+def TDL_DirA : Directive<[Spelling<"dira">]> {
   let allowedClauses = [
     VersionedClause<TDLC_ClauseA>,
     VersionedClause<TDLC_ClauseB>
@@ -54,15 +53,18 @@ def TDL_DirA : Directive<"dira"> {
 // CHECK-EMPTY:
 // CHECK-NEXT:  #include "llvm/ADT/ArrayRef.h"
 // CHECK-NEXT:  #include "llvm/ADT/BitmaskEnum.h"
+// CHECK-NEXT:  #include "llvm/ADT/StringRef.h"
 // CHECK-NEXT:  #include "llvm/Support/Compiler.h"
 // CHECK-NEXT:  #include <cstddef>
+// CHECK-NEXT:  #include <utility>
 // CHECK-EMPTY:
 // CHECK-NEXT:  namespace llvm {
-// CHECK-NEXT:  class StringRef;
 // CHECK-NEXT:  namespace tdl {
 // CHECK-EMPTY:
 // CHECK-NEXT:  LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
 // CHECK-EMPTY:
+// CHECK-NEXT:  struct VersionRange { int Min = 1; int Max = 0x7fffffff; };
+// CHECK-EMPTY:
 // CHECK-NEXT:  enum class Association {
 // CHECK-NEXT:    Block,
 // CHECK-NEXT:    Declaration,
@@ -124,13 +126,20 @@ def TDL_DirA : Directive<"dira"> {
 // CHECK-NEXT:  constexpr auto TDLCV_valc = AKind::TDLCV_valc;
 // CHECK-EMPTY:
 // CHECK-NEXT:  // Enumeration helper functions
-// CHECK-NEXT:  LLVM_ABI Directive getTdlDirectiveKind(StringRef Str);
+// CHECK-NEXT:  LLVM_ABI std::pair<Directive, VersionRange> getTdlDirectiveKindAndVersions(StringRef Str);
+// CHECK-NEXT:  inline Directive getTdlDirectiveKind(StringRef Str) {
+// CHECK-NEXT:   return getTdlDirectiveKindAndVersions(Str).first;
+// CHECK-NEXT:  }
+// CHECK-EMPTY:
+// CHECK-NEXT:  LLVM_ABI StringRef getTdlDirectiveName(Directive D, unsigned Ver = 0);
 // CHECK-EMPTY:
-// CHECK-NEXT:  LLVM_ABI StringRef getTdlDirectiveName(Directive D);
+// CHECK-NEXT:  LLVM_ABI std::pair<Clause, VersionRange> getTdlClauseKindAndVersions(StringRef Str);
 // CHECK-EMPTY:
-// CHECK-NEXT:  LLVM_ABI Clause getTdlClauseKind(StringRef Str);
+// CHECK-NEXT:  inline Clause getTdlClauseKind(StringRef Str) {
+// CHECK-NEXT:    return getTdlClauseKindAndVersions(Str).first;
+// CHECK-NEXT:  }
 // CHECK-EMPTY:
-// CHECK-NEXT:  LLVM_ABI StringRef getTdlClauseName(Clause C);
+// CHECK-NEXT:  LLVM_ABI StringRef getTdlClauseName(Clause C, unsigned Ver = 0);
 // CHECK-EMPTY:
 // CHECK-NEXT:  /// Return true if \p C is a valid clause for \p D in version \p Version.
 // CHECK-NEXT:  LLVM_ABI bool isAllowedClauseForDirective(Directive D, Clause C, unsigned Version);
@@ -312,14 +321,16 @@ def TDL_DirA : Directive<"dira"> {
 // IMPL-NEXT:  #undef GEN_DIRECTIVES_IMPL
 // IMPL-EMPTY:
 // IMPL-NEXT:  #include "llvm/Support/ErrorHandling.h"
+// IMPL-NEXT:  #include <utility>
 // IMPL-EMPTY:
-// IMPL-NEXT:  llvm::tdl::Directive llvm::tdl::getTdlDirectiveKind(llvm::StringRef Str) {
-// IMPL-NEXT:    return StringSwitch<Directive>(Str)
-// IMPL-NEXT:      .Case("dira",TDLD_dira)
-// IMPL-NEXT:      .Default(TDLD_dira);
-// IMPL-NEXT:  }
+// IMPL-NEXT: std::pair<llvm::tdl::Directive, llvm::tdl::VersionRange> llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) {
+// IMPL-NEXT:   VersionRange All{}; // Default-initialized to "all-versions"
+// IMPL-NEXT:   return StringSwitch<std::pair<Directive, VersionRange>>(Str)
+// IMPL-NEXT:     .Case("dira", {TDLD_dira, All})
+// IMPL-NEXT:     .Default({TDLD_dira, All});
+// IMPL-NEXT: }
 // IMPL-EMPTY:
-// IMPL-NEXT:  llvm::StringRef llvm::tdl::getTdlDirectiveName(llvm::tdl::Directive Kind) {
+// IMPL-NEXT:  llvm::StringRef llvm::tdl::getTdlDirectiveName(llvm::tdl::Directive Kind, unsigned) {
 // IMPL-NEXT:    switch (Kind) {
 // IMPL-NEXT:      case TDLD_dira:
 // IMPL-NEXT:        return "dira";
@@ -327,15 +338,16 @@ def TDL_DirA : Directive<"dira"> {
 // IMPL-NEXT:    llvm_unreachable("Invalid Tdl Directive kind");
 // IMPL-NEXT:  }
 // IMPL-EMPTY:
-// IMPL-NEXT:  llvm::tdl::Clause llvm::tdl::getTdlClauseKind(llvm::StringRef Str) {
-// IMPL-NEXT:    return StringSwitch<Clause>(Str)
-// IMPL-NEXT:      .Case("clausea",TDLC_clausea)
-// IMPL-NEXT:      .Case("clauseb",TDLC_clauseb)
-// IMPL-NEXT:      .Case("clausec",TDLC_clausec)
-// IMPL-NEXT:      .Default(TDLC_clauseb);
-// IMPL-NEXT:  }
+// IMPL-NEXT: std::pair<llvm::tdl::Clause, llvm::tdl::VersionRange> llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) {
+// IMPL-NEXT:   VersionRange All{}; // Default-initialized to "all-versions"
+// IMPL-NEXT:   return StringSwitch<std::pair<Clause, VersionRange>>(Str)
+// IMPL-NEXT:     .Case("clausea", {TDLC_clausea, All})
+// IMPL-NEXT:     .Case("clauseb", {TDLC_clauseb, All})
+// IMPL-NEXT:     .Case("clausec", {TDLC_clausec, All})
+// IMPL-NEXT:     .Default({TDLC_clauseb, All});
+// IMPL-NEXT: }
 // IMPL-EMPTY:
-// IMPL-NEXT:  llvm::StringRef llvm::tdl::getTdlClauseName(llvm::tdl::Clause Kind) {
+// IMPL-NEXT:  llvm::StringRef llvm::tdl::getTdlClauseName(llvm::tdl::Clause Kind, unsigned) {
 // IMPL-NEXT:    switch (Kind) {
 // IMPL-NEXT:      case TDLC_clausea:
 // IMPL-NEXT:        return "clausea";
diff --git a/llvm/test/TableGen/directive2.td b/llvm/test/TableGen/directive2.td
index 3de66cfea94b9..ead6aa2637b76 100644
--- a/llvm/test/TableGen/directive2.td
+++ b/llvm/test/TableGen/directive2.td
@@ -13,26 +13,26 @@ def TestDirectiveLanguage : DirectiveLanguage {
   let flangClauseBaseClass = "TdlClause";
 }
 
-def TDLC_ClauseA : Clause<"clausea"> {
+def TDLC_ClauseA : Clause<[Spelling<"clausea">]> {
   let isImplicit = 1;
 }
-def TDLC_ClauseB : Clause<"clauseb"> {
+def TDLC_ClauseB : Clause<[Spelling<"clauseb">]> {
   let isDefault = 1;
   let flangClass = "IntExpr";
   let isValueList = 1;
 }
-def TDLC_ClauseC : Clause<"clausec"> {
+def TDLC_ClauseC : Clause<[Spelling<"clausec">]> {
   let clangClass = "ClauseC";
   let flangClass = "Name";
   let defaultValue = "*";
   let isValueOptional = 1;
 }
-def TDLC_ClauseD : Clause<"claused"> {
+def TDLC_ClauseD : Clause<[Spelling<"claused">]> {
   let clangClass = "ClauseD";
   let isImplicit = 1;
 }
 
-def TDL_DirA : Directive<"dira"> {
+def TDL_DirA : Directive<[Spelling<"dira">]> {
   let allowedClauses = [
     VersionedClause<TDLC_ClauseA, 2, 4>,
     VersionedClause<TDLC_ClauseB, 2>
@@ -46,13 +46,16 @@ def TDL_DirA : Directive<"dira"> {
 // CHECK-NEXT:  #define LLVM_Tdl_INC
 // CHECK-EMPTY:
 // CHECK-NEXT:  #include "llvm/ADT/ArrayRef.h"
+// CHECK-NEXT:  #include "llvm/ADT/StringRef.h"
 // CHECK-NEXT:  #include "llvm/Support/Compiler.h"
 // CHECK-NEXT:  #include <cstddef>
+// CHECK-NEXT:  #include <utility>
 // CHECK-EMPTY:
 // CHECK-NEXT:  namespace llvm {
-// CHECK-NEXT:  class StringRef;
 // CHECK-NEXT:  namespace tdl {
 // CHECK-EMPTY:
+// CHECK-NEXT:  struct VersionRange { int Min = 1; int Max = 0x7fffffff; };
+// CHECK-EMPTY:
 // CHECK-NEXT:  enum class Association {
 // CHECK-NEXT:    Block,
 // CHECK-NEXT:    Declaration,
@@ -99,13 +102,20 @@ def TDL_DirA : Directive<"dira"> {
 // CHECK-NEXT:  static constexpr std::size_t Clause_enumSize = 4;
 // CHECK-EMPTY:
 // CHECK-NEXT:  // Enumeration helper functions
-// CHECK-NEXT:  LLVM_ABI Directive getTdlDirectiveKind(StringRef Str);
+// CHECK-NEXT:  LLVM_ABI std::pair<Directive, VersionRange> getTdlDirectiveKindAndVersions(StringRef Str);
+// CHECK-NEXT:  inline Directive getTdlDirectiveKind(StringRef Str) {
+// CHECK-NEXT:    return getTdlDirectiveKindAndVersions(Str).first;
+// CHECK-NEXT:  }
+// CHECK-EMPTY:
+// CHECK-NEXT:  LLVM_ABI StringRef getTdlDirectiveName(Directive D, unsigned Ver = 0);
 // CHECK-EMPTY:
-// CHECK-NEXT:  LLVM_ABI StringRef getTdlDirectiveName(Directive D);
+// CHECK-NEXT:  LLVM_ABI std::pair<Clause, VersionRange> getTdlClauseKindAndVersions(StringRef Str);
 // CHECK-EMPTY:
-// CHECK-NEXT:  LLVM_ABI Clause getTdlClauseKind(StringRef Str);
+// CHECK-NEXT:  inline Clause getTdlClauseKind(StringRef Str) {
+// CHECK-NEXT:    return getTdlClauseKindAndVersions(Str).first;
+// CHECK-NEXT:  }
 // CHECK-EMPTY:
-// CHECK-NEXT:  LLVM_ABI StringRef getTdlClauseName(Clause C);
+// CHECK-NEXT:  LLVM_ABI StringRef getTdlClauseName(Clause C, unsigned Ver = 0);
 // CHECK-EMPTY:
 // CHECK-NEXT:  /// Return true if \p C is a valid clause for \p D in version \p Version.
 // CHECK-NEXT:  LLVM_ABI bool isAllowedClauseForDirective(Directive D, Clause C, unsigned Version);
@@ -258,14 +268,16 @@ def TDL_DirA : Directive<"dira"> {
 // IMPL-NEXT:  #undef GEN_DIRECTIVES_IMPL
 // IMPL-EMPTY:
 // IMPL-NEXT:  #include "llvm/Support/ErrorHandling.h"
+// IMPL-NEXT:  #include <utility>
 // IMPL-EMPTY:
-// IMPL-NEXT:  llvm::tdl::Directive llvm::tdl::getTdlDirectiveKind(llvm::StringRef Str) {
-// IMPL-NEXT:    return StringSwitch<Directive>(Str)
-// IMPL-NEXT:      .Case("dira",TDLD_dira)
-// IMPL-NEXT:      .Default(TDLD_dira);
-// IMPL-NEXT:  }
+// IMPL-NEXT: std::pair<llvm::tdl::Directive, llvm::tdl::VersionRange> llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) {
+// IMPL-NEXT:   VersionRange All{}; // Default-initialized to "all-versions"
+// IMPL-NEXT:   return StringSwitch<std::pair<Directive, VersionRange>>(Str)
+// IMPL-NEXT:     .Case("dira", {TDLD_dira, All})
+// IMPL-NEXT:     .Default({TDLD_dira, All});
+// IMPL-NEXT: }
 // IMPL-EMPTY:
-// IMPL-NEXT:  llvm::StringRef llvm::tdl::getTdlDirectiveName(llvm::tdl::Directive Kind) {
+// IMPL-NEXT:  llvm::StringRef llvm::tdl::getTdlDirectiveName(llvm::tdl::Directive Kind, unsigned) {
 // IMPL-NEXT:    switch (Kind) {
 // IMPL-NEXT:      case TDLD_dira:
 // IMPL-NEXT:        return "dira";
@@ -273,16 +285,17 @@ def TDL_DirA : Directive<"dira"> {
 // IMPL-NEXT:    llvm_unreachable("Invalid Tdl Directive kind");
 // IMPL-NEXT:  }
 // IMPL-EMPTY:
-// IMPL-NEXT:  llvm::tdl::Clause llvm::tdl::getTdlClauseKind(llvm::StringRef Str) {
-// IMPL-NEXT:    return StringSwitch<Clause>(Str)
-// IMPL-NEXT:      .Case("clausea",TDLC_clauseb)
-// IMPL-NEXT:      .Case("clauseb",TDLC_clauseb)
-// IMPL-NEXT:      .Case("clausec",TDLC_clausec)
-// IMPL-NEXT:      .Case("claused",TDLC_clauseb)
-// IMPL-NEXT:      .Default(TDLC_clauseb);
-// IMPL-NEXT:  }
+// IMPL-NEXT: std::pair<llvm::tdl::Clause, llvm::tdl::VersionRange> llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) {
+// IMPL-NEXT:   VersionRange All{}; // Default-initialized to "all-versions"
+// IMPL-NEXT:   return StringSwitch<std::pair<Clause, VersionRange>>(Str)
+// IMPL-NEXT:     .Case("clausea", {TDLC_clauseb, All})
+// IMPL-NEXT:     .Case("clauseb", {TDLC_clauseb, All})
+// IMPL-NEXT:     .Case("clausec", {TDLC_clausec, All})
+// IMPL-NEXT:     .Case("claused", {TDLC_clauseb, All})
+// IMPL-NEXT:     .Default({TDLC_clauseb, All});
+// IMPL-NEXT: }
 // IMPL-EMPTY:
-// IMPL-NEXT:  llvm::StringRef llvm::tdl::getTdlClauseName(llvm::tdl::Clause Kind) {
+// IMPL-NEXT:  llvm::StringRef llvm::tdl::getTdlClauseName(llvm::tdl::Clause Kind, unsigned) {
 // IMPL-NEXT:    switch (Kind) {
 // IMPL-NEXT:      case TDLC_clausea:
 // IMPL-NEXT:        return "clausea";
diff --git a/llvm/test/TableGen/directive3.td b/llvm/test/TableGen/directive3.td
index 2a82b5ebcb493..a9e1f04d4dec6 100644
--- a/llvm/test/TableGen/directive3.td
+++ b/llvm/test/TableGen/directive3.td
@@ -7,20 +7,20 @@ def TestDirectiveLanguage : DirectiveLanguage {
   let name = "TdlError";
 }
 
-def TDLC_ClauseA : Clause<"clausea"> {
+def TDLC_ClauseA : Clause<[Spelling<"clausea">]> {
   let isDefault = 1;
 }
 
-def TDLC_ClauseB : Clause<"clauseb"> {
+def TDLC_ClauseB : Clause<[Spelling<"clauseb">]> {
 }
 
-def TDLC_ClauseC : Clause<"clausec"> {
+def TDLC_ClauseC : Clause<[Spelling<"clausec">]> {
 }
 
-def TDLC_ClauseD : Clause<"claused"> {
+def TDLC_ClauseD : Clause<[Spelling<"claused">]> {
 }
 
-def TDL_DirA : Directive<"dira"> {
+def TDL_DirA : Directive<[Spelling<"dira">]> {
   let allowedClauses = [
     VersionedClause<TDLC_ClauseA>,
     VersionedClause<TDLC_ClauseB>,
diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
index bd6c543e1741a..e1e41b3ecb584 100644
--- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
@@ -24,6 +24,7 @@
 #include "llvm/TableGen/TableGenBackend.h"
 
 #include <numeric>
+#include <string>
 #include <vector>
 
 using namespace llvm;
@@ -193,10 +194,11 @@ static bool hasDuplicateClauses(ArrayRef<const Record *> Clauses,
                                 StringSet<> &CrtClauses) {
   bool HasError = false;
   for (const VersionedClause VerClause : Clauses) {
-    const auto InsRes = CrtClauses.insert(VerClause.getClause().getName());
+    StringRef Name = VerClause.getClause().getRecordName();
+    const auto InsRes = CrtClauses.insert(Name);
     if (!InsRes.second) {
-      PrintError("Clause " + VerClause.getClause().getRecordName() +
-                 " already defined on directive " + Directive.getRecordName());
+      PrintError("Clause " + Name + " already defined on directive " +
+                 Directive.getRecordName());
       HasError = true;
     }
   }
@@ -267,11 +269,12 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
   if (DirLang.hasEnableBitmaskEnumInNamespace())
     OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n";
 
+  OS << "#include \"llvm/ADT/StringRef.h\"\n";
   OS << "#include \"llvm/Support/Compiler.h\"\n";
   OS << "#include <cstddef>\n"; // for size_t
+  OS << "#include <utility>\n"; // for std::pair
   OS << "\n";
   OS << "namespace llvm {\n";
-  OS << "class StringRef;\n";
 
   // Open namespaces defined in the directive language
   SmallVector<StringRef, 2> Namespaces;
@@ -282,6 +285,13 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
   if (DirLang.hasEnableBitmaskEnumInNamespace())
     OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
 
+#define AS_STRING_HELPER_TO_GET_THE_ARGUMENT_MACRO_EXPANDED(x) #x
+#define AS_STRING(x) AS_STRING_HELPER_TO_GET_THE_ARGUMENT_MACRO_EXPANDED(x)
+  OS << "\n";
+  OS << AS_STRING(STRUCT_VERSION_RANGE) << ";\n";
+#undef AS_STRING
+#undef AS_STRING_HELPER_TO_GET_THE_ARGUMENT_MACRO_EXPANDED
+
   // Emit Directive associations
   std::vector<const Record *> Associations;
   copy_if(DirLang.getAssociations(), std::back_inserter(Associations),
@@ -313,22 +323,32 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
   // Generic function signatures
   OS << "\n";
   OS << "// Enumeration helper functions\n";
-  OS << "LLVM_ABI Directive get" << Lang << "DirectiveKind(StringRef Str);\n";
+
+  OS << "LLVM_ABI std::pair<Directive, VersionRange> get" << Lang
+     << "DirectiveKindAndVersions(StringRef Str);\n";
+
+  OS << "inline Directive get" << Lang << "DirectiveKind(StringRef Str) {\n";
+  OS << "  return get" << Lang << "DirectiveKindAndVersions(Str).first;\n";
+  OS << "}\n";
   OS << "\n";
 
-  // For OpenMP the signature is
-  //   getOpenMPDirectiveName(Directive D, unsigned V)
-  OS << "LLVM_ABI StringRef get" << DirLang.getName()
-     << "DirectiveName(Directive D";
-  if (DirLang.getCppNamespace() == "omp")
-    OS << ", unsigned = 0";
-  OS << ");\n";
+  OS << "LLVM_ABI StringRef get" << Lang
+     << "DirectiveName(Directive D, unsigned Ver = 0);\n";
   OS << "\n";
 
-  OS << "LLVM_ABI Clause get" << Lang << "ClauseKind(StringRef Str);\n";
+  OS << "LLVM_ABI std::pair<Clause, VersionRange> get" << Lang
+     << "ClauseKindAndVersions(StringRef Str);\n";
   OS << "\n";
-  OS << "LLVM_ABI StringRef get" << Lang << "ClauseName(Clause C);\n";
+
+  OS << "inline Clause get" << Lang << "ClauseKind(StringRef Str) {\n";
+  OS << "  return get" << Lang << "ClauseKindAndVersions(Str).first;\n";
+  OS << "}\n";
   OS << "\n";
+
+  OS << "LLVM_ABI StringRef get" << Lang
+     << "ClauseName(Clause C, unsigned Ver = 0);\n";
+  OS << "\n";
+
   OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p "
      << "Version.\n";
   OS << "LLVM_ABI bool isAllowedClauseForDirective(Directive D, "
@@ -359,25 +379,23 @@ static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS,
                             StringRef Prefix) {
   StringRef Lang = DirLang.getName();
   std::string Qual = getQualifier(DirLang);
-  // For OpenMP the "Directive" signature is
-  //   getOpenMPDirectiveName(Directive D, unsigned V)
   OS << "\n";
   OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual
-     << Enum << " Kind";
-  if (DirLang.getCppNamespace() == "omp" && Enum == "Directive")
-    OS << ", unsigned";
-  OS << ") {\n";
+     << Enum << " Kind, unsigned) {\n";
   OS << "  switch (Kind) {\n";
   for (const Record *R : Records) {
     OS << "    case " << getIdentifierName(R, Prefix) << ":\n";
-    OS << "      return \"" << BaseRecord(R).getName() << "\";\n";
+    // FIXME: This will need to recognize different spellings for different
+    // versions.
+    OS << "      return \"" << BaseRecord(R).getSpellingForIdentifier()
+       << "\";\n";
   }
   OS << "  }\n"; // switch
   OS << "  llvm_unreachable(\"Invalid " << Lang << " " << Enum << " kind\");\n";
   OS << "}\n";
 }
 
-// Generate function implementation for get<Enum>Kind(StringRef Str)
+// Generate function implementation for get<Enum>KindAndVersions(StringRef Str)
 static void generateGetKind(ArrayRef<const Record *> Records, raw_ostream &OS,
                             StringRef Enum, const DirectiveLanguage &DirLang,
                             StringRef Prefix, bool ImplicitAsUnknown) {
@@ -394,21 +412,29 @@ static void generateGetKind(ArrayRef<const Record *> Records, raw_ostream &OS,
   std::string Qual = getQualifier(DirLang);
   std::string DefaultName = getIdentifierName(*DefaultIt, Prefix);
 
+  // std::pair<<Enum>, VersionRange>
+  // get<DirLang><Enum>KindAndVersions(StringRef Str);
   OS << "\n";
-  OS << Qual << Enum << " " << Qual << "get" << DirLang.getName() << Enum
-     << "Kind(llvm::StringRef Str) {\n";
-  OS << "  return StringSwitch<" << Enum << ">(Str)\n";
+  OS << "std::pair<" << Qual << Enum << ", " << Qual << "VersionRange> " << Qual
+     << "get" << DirLang.getName() << Enum
+     << "KindAndVersions(llvm::StringRef Str) {\n";
+  OS << "  VersionRange All{}; // Default-initialized to \"all-versions\"\n";
+  OS << "  return StringSwitch<std::pair<" << Enum << ", "
+     << "VersionRange>>(Str)\n";
 
   for (const Record *R : Records) {
     BaseRecord Rec(R);
+    // FIXME: This will need to recognize different spellings for different
+    // versions.
+    StringRef Name = Rec.getSpellingForIdentifier();
     if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) {
-      OS << "    .Case(\"" << Rec.getName() << "\"," << DefaultName << ")\n";
+      OS << "    .Case(\"" << Name << "\", {" << DefaultName << ", All})\n";
     } else {
-      OS << "    .Case(\"" << Rec.getName() << "\","
-         << getIdentifierName(R, Prefix) << ")\n";
+      OS << "    .Case(\"" << Name << "\", {"
+         << getIdentifierName(R, Prefix) << ", All})\n";
     }
   }
-  OS << "    .Default(" << DefaultName << ");\n";
+  OS << "    .Default({" << DefaultName << ", All});\n";
   OS << "}\n";
 }
 
@@ -430,7 +456,7 @@ static void generateGetClauseVal(const DirectiveLanguage &DirLang,
     });
 
     if (DefaultIt == ClauseVals.end()) {
-      PrintError("At least one val in Clause " + C.getFormattedName() +
+      PrintError("At least one val in Clause " + C.getRecordName() +
                  " must be defined as default.");
       return;
     }
@@ -438,8 +464,8 @@ static void generateGetClauseVal(const DirectiveLanguage &DirLang,
 
     StringRef Enum = C.getEnumName();
     if (Enum.empty()) {
-      PrintError("enumClauseValue field not set in Clause" +
-                 C.getFormattedName() + ".");
+      PrintError("enumClauseValue field not set in Clause" + C.getRecordName() +
+                 ".");
       return;
     }
 
@@ -599,7 +625,10 @@ static void emitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS,
   // (such as "end declare target").
   DenseSet<int> EndDirectives;
   for (auto [Rec, Id] : DirId) {
-    if (Directive(Rec).getName().starts_with_insensitive("end "))
+    // FIXME: This will need to recognize different spellings for different
+    // versions.
+    StringRef Name = Directive(Rec).getSpellingForIdentifier();
+    if (Name.starts_with_insensitive("end "))
       EndDirectives.insert(Id);
   }
 
@@ -710,7 +739,7 @@ static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang,
   };
 
   auto ErrorPrefixFor = [&](Directive D) -> std::string {
-    return (Twine("Directive '") + D.getName() + "' in namespace '" +
+    return (Twine("Directive '") + D.getRecordName() + "' in namespace '" +
             DirLang.getCppNamespace() + "' ")
         .str();
   };
@@ -752,7 +781,6 @@ static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang,
     // Compute the association from leaf constructs.
     std::vector<const Record *> Leaves = D.getLeafConstructs();
     if (Leaves.empty()) {
-      errs() << D.getName() << '\n';
       PrintFatalError(ErrorPrefixFor(D) +
                       "requests association to be computed from leaves, "
                       "but it has no leaves");
@@ -899,7 +927,7 @@ static void generateDirectiveClauseSets(const DirectiveLanguage &DirLang,
 
   for (const Directive Dir : DirLang.getDirectives()) {
     OS << "\n";
-    OS << "// Sets for " << Dir.getName() << "\n";
+    OS << "// Sets for " << Dir.getSpellingForIdentifier() << "\n";
 
     generateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir,
                       DirLang, FE);
@@ -1034,8 +1062,11 @@ static void generateFlangClauseUnparse(const DirectiveLanguage &DirLang,
   for (const Clause Clause : DirLang.getClauses()) {
     if (Clause.skipFlangUnparser())
       continue;
+    // The unparser doesn't know the effective version, so just pick some
+    // spelling.
+    StringRef SomeSpelling = Clause.getSpellingForIdentifier();
     std::string Parser = Clause.getFormattedParserClassName();
-    std::string Upper = Clause.getName().upper();
+    std::string Upper = SomeSpelling.upper();
 
     if (!Clause.getFlangClass().empty()) {
       if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) {
@@ -1125,9 +1156,9 @@ getSpellingTexts(ArrayRef<const Record *> Records) {
   std::vector<RecordWithText> List;
   for (const Record *R : Records) {
     Clause C(R);
-    List.push_back(std::make_pair(R, C.getName()));
-    llvm::transform(C.getAliases(), std::back_inserter(List),
-                    [R](StringRef S) { return std::make_pair(R, S); });
+    llvm::transform(
+        C.getSpellings(), std::back_inserter(List),
+        [R](Spelling::Value V) { return std::make_pair(R, V.first); });
   }
   return List;
 }
@@ -1305,7 +1336,9 @@ void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
   StringRef DPrefix = DirLang.getDirectivePrefix();
   StringRef CPrefix = DirLang.getClausePrefix();
 
-  OS << "\n#include \"llvm/Support/ErrorHandling.h\"\n";
+  OS << "\n";
+  OS << "#include \"llvm/Support/ErrorHandling.h\"\n";
+  OS << "#include <utility>\n";
 
   // getDirectiveKind(StringRef Str)
   generateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang, DPrefix,
diff --git a/mlir/test/mlir-tblgen/directive-common.td b/mlir/test/mlir-tblgen/directive-common.td
index 54e0d14ca83dd..78747b82f1f4a 100644
--- a/mlir/test/mlir-tblgen/directive-common.td
+++ b/mlir/test/mlir-tblgen/directive-common.td
@@ -11,7 +11,7 @@ def TDLCV_vala : EnumVal<"vala",1,1> {}
 def TDLCV_valb : EnumVal<"valb",2,1> {}
 def TDLCV_valc : EnumVal<"valc",3,0> { let isDefault = 1; }
 
-def TDLC_ClauseA : Clause<"clausea"> {
+def TDLC_ClauseA : Clause<[Spelling<"clausea">]> {
   let flangClass = "TdlClauseA";
   let enumClauseValue = "AKind";
   let allowedClauseValues = [



More information about the llvm-branch-commits mailing list