[llvm-branch-commits] [clang] 415fab6 - [TableGen] Eliminate the 'code' type

Paul C. Anagnostopoulos via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Dec 3 07:25:21 PST 2020


Author: Paul C. Anagnostopoulos
Date: 2020-12-03T10:19:11-05:00
New Revision: 415fab6f67b4db59abe533130272d55b4efbf0cb

URL: https://github.com/llvm/llvm-project/commit/415fab6f67b4db59abe533130272d55b4efbf0cb
DIFF: https://github.com/llvm/llvm-project/commit/415fab6f67b4db59abe533130272d55b4efbf0cb.diff

LOG: [TableGen] Eliminate the 'code' type

Update the documentation.

Rework various backends that relied on the code type.

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

Added: 
    

Modified: 
    clang/utils/TableGen/ClangOptionDocEmitter.cpp
    llvm/docs/TableGen/BackEnds.rst
    llvm/docs/TableGen/BackGuide.rst
    llvm/docs/TableGen/ProgRef.rst
    llvm/include/llvm/TableGen/Error.h
    llvm/include/llvm/TableGen/Record.h
    llvm/include/llvm/TableGen/SearchableTable.td
    llvm/lib/TableGen/Error.cpp
    llvm/lib/TableGen/JSONBackend.cpp
    llvm/lib/TableGen/Record.cpp
    llvm/lib/TableGen/TGLexer.cpp
    llvm/lib/TableGen/TGLexer.h
    llvm/lib/TableGen/TGParser.cpp
    llvm/lib/Target/AMDGPU/MIMGInstructions.td
    llvm/test/TableGen/code.td
    llvm/test/TableGen/generic-tables.td
    llvm/test/TableGen/interleave.td
    llvm/test/TableGen/unterminated-code-block.td
    llvm/utils/TableGen/AsmWriterEmitter.cpp
    llvm/utils/TableGen/DFAEmitter.cpp
    llvm/utils/TableGen/GICombinerEmitter.cpp
    llvm/utils/TableGen/RISCVCompressInstEmitter.cpp
    llvm/utils/TableGen/SearchableTableEmitter.cpp
    mlir/include/mlir/TableGen/Operator.h
    mlir/lib/TableGen/Attribute.cpp
    mlir/lib/TableGen/Dialect.cpp
    mlir/lib/TableGen/Operator.cpp
    mlir/lib/TableGen/Pattern.cpp
    mlir/lib/TableGen/Type.cpp
    mlir/lib/TableGen/TypeDef.cpp
    mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp

Removed: 
    


################################################################################
diff  --git a/clang/utils/TableGen/ClangOptionDocEmitter.cpp b/clang/utils/TableGen/ClangOptionDocEmitter.cpp
index 23aa31cc732f..0e079b6b505a 100644
--- a/clang/utils/TableGen/ClangOptionDocEmitter.cpp
+++ b/clang/utils/TableGen/ClangOptionDocEmitter.cpp
@@ -217,8 +217,6 @@ std::string getRSTStringWithTextFallback(const Record *R, StringRef Primary,
       StringRef Value;
       if (auto *SV = dyn_cast_or_null<StringInit>(V->getValue()))
         Value = SV->getValue();
-      else if (auto *CV = dyn_cast_or_null<CodeInit>(V->getValue()))
-        Value = CV->getValue();
       if (!Value.empty())
         return Field == Primary ? Value.str() : escapeRST(Value);
     }

diff  --git a/llvm/docs/TableGen/BackEnds.rst b/llvm/docs/TableGen/BackEnds.rst
index b4ccdf95485e..1e1a4e71a1fd 100644
--- a/llvm/docs/TableGen/BackEnds.rst
+++ b/llvm/docs/TableGen/BackEnds.rst
@@ -693,8 +693,8 @@ This class provides six fields.
   table that holds the entries. If unspecified, the ``FilterClass`` name is
   used.
 
-* ``list<string> Fields``. A list of the names of the fields in the
-  collected records that contain the data for the table entries. The order of
+* ``list<string> Fields``. A list of the names of the fields *in the
+  collected records* that contain the data for the table entries. The order of
   this list determines the order of the values in the C++ initializers. See
   below for information about the types of these fields.
 
@@ -706,13 +706,26 @@ This class provides six fields.
 
 * ``bit PrimaryKeyEarlyOut``. See the third example below.
 
-TableGen attempts to deduce the type of each of the table fields. It can
-deduce ``bit``, ``bits<n>``, ``string``, ``Intrinsic``, and ``Instruction``.
-These can be used in the primary key. TableGen also deduces ``code``, but it
-cannot be used in the primary key. Any other field types must be specified
+TableGen attempts to deduce the type of each of the table fields so that it
+can format the C++ initializers in the emitted table. It can deduce ``bit``,
+``bits<n>``, ``string``, ``Intrinsic``, and ``Instruction``.  These can be
+used in the primary key. Any other field types must be specified
 explicitly; this is done as shown in the second example below. Such fields
 cannot be used in the primary key.
 
+One special case of the field type has to do with code. Arbitrary code is
+represented by a string, but has to be emitted as a C++ initializer without
+quotes. If the code field was defined using a code literal (``[{...}]``),
+then TableGen will know to emit it without quotes. However, if it was
+defined using a string literal or complex string expression, then TableGen
+will not know. In this case, you can force TableGen to treat the field as
+code by including the following line in the ``GenericTable`` record, where
+*xxx* is the code field name.
+
+.. code-block:: text
+
+  string TypeOf_xxx = "code";
+
 Here is an example where TableGen can deduce the field types. Note that the
 table entry records are anonymous; the names of entry records are
 irrelevant.
@@ -793,7 +806,7 @@ pointer if no entry is found.
 
 This example includes a field whose type TableGen cannot deduce. The ``Kind``
 field uses the enumerated type ``CEnum`` defined above. To inform TableGen
-of the type, the class derived from ``GenericTable`` must include a field
+of the type, the record derived from ``GenericTable`` must include a string field
 named ``TypeOf_``\ *field*, where *field* is the name of the field whose type
 is required.
 
@@ -802,7 +815,7 @@ is required.
   def CTable : GenericTable {
     let FilterClass = "CEntry";
     let Fields = ["Name", "Kind", "Encoding"];
-    GenericEnum TypeOf_Kind = CEnum;
+    string TypeOf_Kind = "CEnum";
     let PrimaryKey = ["Encoding"];
     let PrimaryKeyName = "lookupCEntryByEncoding";
   }

diff  --git a/llvm/docs/TableGen/BackGuide.rst b/llvm/docs/TableGen/BackGuide.rst
index 515eeab2403a..f21910c56ac2 100644
--- a/llvm/docs/TableGen/BackGuide.rst
+++ b/llvm/docs/TableGen/BackGuide.rst
@@ -287,9 +287,9 @@ value. The static function ``get()`` can be used to obtain the singleton
 
 This class, a subclass of ``Init``, acts as the parent class of the classes
 that represent specific value types (except for the unset value). These
-classes include ``BitInit``, ``BitsInit``, ``CodeInit``, ``DagInit``,
-``DefInit``, ``IntInit``, ``ListInit``, and ``StringInit``. (There are
-additional derived types used by the TableGen parser.)
+classes include ``BitInit``, ``BitsInit``, ``DagInit``, ``DefInit``,
+``IntInit``, ``ListInit``, and ``StringInit``. (There are additional derived
+types used by the TableGen parser.)
 
 This class includes a data member that specifies the ``RecTy`` type of the
 value. It provides a function to get that ``RecTy`` type.
@@ -330,18 +330,6 @@ The class provides the following additional functions.
 
 * A function that gets a bit specified by an integer index.
 
-``CodeInit``
-~~~~~~~~~~~~
-
-The ``CodeInit`` class is a subclass of ``TypedInit``. Its instances
-represent arbitrary-length strings produced from ``code`` literals in the
-TableGen files. It includes a data member that contains a ``StringRef`` of
-the value.
-
-The class provides the usual ``get()`` and ``getValue()`` functions. The
-latter function returns the ``StringRef``.
-
-
 ``DagInit``
 ~~~~~~~~~~~
 

diff  --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index c805afc8ccc1..342b91a0c437 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -167,10 +167,11 @@ TableGen has two kinds of string literals:
 
 .. productionlist::
    TokString: '"' (non-'"' characters and escapes) '"'
-   TokCodeFragment: "[{" (shortest text not containing "}]") "}]"
+   TokCode: "[{" (shortest text not containing "}]") "}]"
 
-A :token:`TokCodeFragment` is nothing more than a multi-line string literal
-delimited by ``[{`` and ``}]``. It can break across lines.
+A :token:`TokCode` is nothing more than a multi-line string literal
+delimited by ``[{`` and ``}]``. It can break across lines and the
+line breaks are retained in the string.
 
 The current implementation accepts the following escape sequences::
 
@@ -254,7 +255,7 @@ high-level types (e.g., ``dag``). This flexibility allows you to describe a
 wide range of records conveniently and compactly.
 
 .. productionlist::
-   Type: "bit" | "int" | "string" | "code" | "dag"
+   Type: "bit" | "int" | "string" | "dag"
        :| "bits" "<" `TokInteger` ">"
        :| "list" "<" `Type` ">"
        :| `ClassID`
@@ -271,11 +272,6 @@ wide range of records conveniently and compactly.
     The ``string`` type represents an ordered sequence of characters of arbitrary
     length.
 
-``code``
-    The ``code`` type represents a code fragment. The values are the same as
-    those for the ``string`` type; the ``code`` type is provided just to indicate
-    the programmer's intention.
-
 ``bits<``\ *n*\ ``>``
     The ``bits`` type is a fixed-sized integer of arbitrary length *n* that
     is treated as separate bits. These bits can be accessed individually.
@@ -348,12 +344,12 @@ Simple values
 The :token:`SimpleValue` has a number of forms.
 
 .. productionlist::
-   SimpleValue: `TokInteger` | `TokString`+ | `TokCodeFragment`
+   SimpleValue: `TokInteger` | `TokString`+ | `TokCode`
 
-A value can be an integer literal, a string literal, or a code fragment
-literal. Multiple adjacent string literals are concatenated as in C/C++; the
-simple value is the concatenation of the strings. Code fragments become
-strings and then are indistinguishable from them.
+A value can be an integer literal, a string literal, or a code literal.
+Multiple adjacent string literals are concatenated as in C/C++; the simple
+value is the concatenation of the strings. Code literals become strings and
+are then indistinguishable from them.
 
 .. productionlist::
    SimpleValue2: "true" | "false"
@@ -616,14 +612,15 @@ name of a multiclass.
 
 .. productionlist::
    Body: ";" | "{" `BodyItem`* "}"
-   BodyItem: `Type` `TokIdentifier` ["=" `Value`] ";"
+   BodyItem: (`Type` | "code") `TokIdentifier` ["=" `Value`] ";"
            :| "let" `TokIdentifier` ["{" `RangeList` "}"] "=" `Value` ";"
            :| "defvar" `TokIdentifier` "=" `Value` ";"
 
 A field definition in the body specifies a field to be included in the class
 or record. If no initial value is specified, then the field's value is
 uninitialized. The type must be specified; TableGen will not infer it from
-the value.
+the value. The keyword ``code`` may be used to emphasize that the field
+has a string value that is code.
 
 The ``let`` form is used to reset a field to a new value. This can be done
 for fields defined directly in the body or fields inherited from

diff  --git a/llvm/include/llvm/TableGen/Error.h b/llvm/include/llvm/TableGen/Error.h
index a742e9e1606c..f63b50ad786c 100644
--- a/llvm/include/llvm/TableGen/Error.h
+++ b/llvm/include/llvm/TableGen/Error.h
@@ -22,6 +22,7 @@ namespace llvm {
 void PrintNote(const Twine &Msg);
 void PrintNote(ArrayRef<SMLoc> NoteLoc, const Twine &Msg);
 
+LLVM_ATTRIBUTE_NORETURN void PrintFatalNote(const Twine &Msg);
 LLVM_ATTRIBUTE_NORETURN void PrintFatalNote(ArrayRef<SMLoc> ErrorLoc,
                                             const Twine &Msg);
 LLVM_ATTRIBUTE_NORETURN void PrintFatalNote(const Record *Rec,
@@ -37,6 +38,7 @@ void PrintError(const Twine &Msg);
 void PrintError(ArrayRef<SMLoc> ErrorLoc, const Twine &Msg);
 void PrintError(const char *Loc, const Twine &Msg);
 void PrintError(const Record *Rec, const Twine &Msg);
+void PrintError(const RecordVal *RecVal, const Twine &Msg);
 
 LLVM_ATTRIBUTE_NORETURN void PrintFatalError(const Twine &Msg);
 LLVM_ATTRIBUTE_NORETURN void PrintFatalError(ArrayRef<SMLoc> ErrorLoc,

diff  --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h
index 20b786dc6e42..1c3ec5fb21f5 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -58,7 +58,6 @@ class RecTy {
   enum RecTyKind {
     BitRecTyKind,
     BitsRecTyKind,
-    CodeRecTyKind,
     IntRecTyKind,
     StringRecTyKind,
     ListRecTyKind,
@@ -138,24 +137,6 @@ class BitsRecTy : public RecTy {
   bool typeIsA(const RecTy *RHS) const override;
 };
 
-/// 'code' - Represent a code fragment
-class CodeRecTy : public RecTy {
-  static CodeRecTy Shared;
-
-  CodeRecTy() : RecTy(CodeRecTyKind) {}
-
-public:
-  static bool classof(const RecTy *RT) {
-    return RT->getRecTyKind() == CodeRecTyKind;
-  }
-
-  static CodeRecTy *get() { return &Shared; }
-
-  std::string getAsString() const override { return "code"; }
-
-  bool typeIsConvertibleTo(const RecTy *RHS) const override;
-};
-
 /// 'int' - Represent an integer value of no particular size
 class IntRecTy : public RecTy {
   static IntRecTy Shared;
@@ -306,7 +287,6 @@ class Init {
     IK_FirstTypedInit,
     IK_BitInit,
     IK_BitsInit,
-    IK_CodeInit,
     IK_DagInit,
     IK_DefInit,
     IK_FieldInit,
@@ -597,16 +577,18 @@ class IntInit : public TypedInit {
 
 /// "foo" - Represent an initialization by a string value.
 class StringInit : public TypedInit {
-////  enum StringFormat {
-////    SF_String,  // Format as "text"
-////    SF_Code,    // Format as [{text}]
-////  };
+public:
+  enum StringFormat {
+    SF_String, // Format as "text"
+    SF_Code,   // Format as [{text}]
+  };
 
+private:
   StringRef Value;
-////  StringFormat Format;
+  StringFormat Format;
 
-  explicit StringInit(StringRef V)
-      : TypedInit(IK_StringInit, StringRecTy::get()), Value(V) {}
+  explicit StringInit(StringRef V, StringFormat Fmt)
+      : TypedInit(IK_StringInit, StringRecTy::get()), Value(V), Format(Fmt) {}
 
 public:
   StringInit(const StringInit &) = delete;
@@ -616,48 +598,25 @@ class StringInit : public TypedInit {
     return I->getKind() == IK_StringInit;
   }
 
-  static StringInit *get(StringRef);
-
-  StringRef getValue() const { return Value; }
-
-  Init *convertInitializerTo(RecTy *Ty) const override;
+  static StringInit *get(StringRef, StringFormat Fmt = SF_String);
 
-  bool isConcrete() const override { return true; }
-  std::string getAsString() const override { return "\"" + Value.str() + "\""; }
-
-  std::string getAsUnquotedString() const override {
-    return std::string(Value);
-  }
-
-  Init *getBit(unsigned Bit) const override {
-    llvm_unreachable("Illegal bit reference off string");
-  }
-};
-
-class CodeInit : public TypedInit {
-  StringRef Value;
-
-  explicit CodeInit(StringRef V)
-      : TypedInit(IK_CodeInit, static_cast<RecTy *>(CodeRecTy::get())),
-        Value(V) {}
-
-public:
-  CodeInit(const StringInit &) = delete;
-  CodeInit &operator=(const StringInit &) = delete;
-
-  static bool classof(const Init *I) {
-    return I->getKind() == IK_CodeInit;
+  static StringFormat determineFormat(StringFormat Fmt1, StringFormat Fmt2) {
+    return (Fmt1 == SF_Code || Fmt2 == SF_Code) ? SF_Code : SF_String;
   }
 
-  static CodeInit *get(StringRef);
-
   StringRef getValue() const { return Value; }
+  StringFormat getFormat() const { return Format; }  
+  bool hasCodeFormat() const { return Format == SF_Code; }
 
   Init *convertInitializerTo(RecTy *Ty) const override;
 
   bool isConcrete() const override { return true; }
+
   std::string getAsString() const override {
-    return "[{" + Value.str() + "}]";
+    if (Format == SF_String)
+      return "\"" + Value.str() + "\"";
+    else
+      return "[{" + Value.str() + "}]";
   }
 
   std::string getAsUnquotedString() const override {
@@ -1438,6 +1397,9 @@ class RecordVal {
   /// Get the type of the field value as a RecTy.
   RecTy *getType() const { return TyAndPrefix.getPointer(); }
 
+  /// Get the type of the field for printing purposes.
+  std::string getPrintType() const;
+
   /// Get the value of the field as an Init.
   Init *getValue() const { return Value; }
 
@@ -1675,11 +1637,6 @@ class Record {
   /// not a string and llvm::Optional() if the field does not exist.
   llvm::Optional<StringRef> getValueAsOptionalString(StringRef FieldName) const;
 
-  /// This method looks up the specified field and returns
-  /// its value as a string, throwing an exception if the field if the value is
-  /// not a code block and llvm::Optional() if the field does not exist.
-  llvm::Optional<StringRef> getValueAsOptionalCode(StringRef FieldName) const;
-
   /// This method looks up the specified field and returns
   /// its value as a BitsInit, throwing an exception if the field does not exist
   /// or if the value is not the right type.

diff  --git a/llvm/include/llvm/TableGen/SearchableTable.td b/llvm/include/llvm/TableGen/SearchableTable.td
index 32b9829aa072..61dfa5c70706 100644
--- a/llvm/include/llvm/TableGen/SearchableTable.td
+++ b/llvm/include/llvm/TableGen/SearchableTable.td
@@ -67,9 +67,13 @@ class GenericTable {
   // List of the names of fields of collected records that contain the data for
   // table entries, in the order that is used for initialization in C++.
   //
-  // For each field of the table named XXX, TableGen will look for a value
-  // called TypeOf_XXX and use that as a more detailed description of the
-  // type of the field if present. This is required for fields whose type
+  // TableGen needs to know the type of the fields so that it can format
+  // the initializers correctly. It can infer the type of bit, bits, string,
+  // Intrinsic, and Instruction values. 
+  //
+  // For each field of the table named xxx, TableGen will look for a field
+  // named TypeOf_xxx and use that as a more detailed description of the
+  // type of the field. This is required for fields whose type
   // cannot be deduced automatically, such as enum fields. For example:
   //
   //   def MyEnum : GenericEnum {
@@ -85,15 +89,15 @@ class GenericTable {
   //   def MyTable : GenericTable {
   //     let FilterClass = "MyTableEntry";
   //     let Fields = ["V", ...];
-  //     GenericEnum TypeOf_V = MyEnum;
+  //     string TypeOf_V = "MyEnum";
   //   }
   //
-  // Fields of type bit, bits<N>, string, Intrinsic, and Instruction (or
-  // derived classes of those) are supported natively.
+  // If a string field was initialized with a code literal, TableGen will
+  // emit the code verbatim. However, if a string field was initialized
+  // in some other way, but should be interpreted as code, then a TypeOf_xxx
+  // field is necessary, with a value of "code":
   //
-  // Additionally, fields of type `code` can appear, where the value is used
-  // verbatim as an initializer. However, these fields cannot be used as
-  // search keys.
+  //     string TypeOf_Predicate = "code";
   list<string> Fields;
 
   // (Optional) List of fields that make up the primary key.

diff  --git a/llvm/lib/TableGen/Error.cpp b/llvm/lib/TableGen/Error.cpp
index 015b1d350197..eed4de67942a 100644
--- a/llvm/lib/TableGen/Error.cpp
+++ b/llvm/lib/TableGen/Error.cpp
@@ -52,6 +52,13 @@ void PrintNote(ArrayRef<SMLoc> NoteLoc, const Twine &Msg) {
 
 // Functions to print fatal notes.
 
+void PrintFatalNote(const Twine &Msg) {
+  PrintNote(Msg);
+  // The following call runs the file cleanup handlers.
+  sys::RunInterruptHandlers();
+  std::exit(1);
+}
+
 void PrintFatalNote(ArrayRef<SMLoc> NoteLoc, const Twine &Msg) {
   PrintNote(NoteLoc, Msg);
   // The following call runs the file cleanup handlers.
@@ -107,6 +114,12 @@ void PrintError(const Record *Rec, const Twine &Msg) {
   PrintMessage(Rec->getLoc(), SourceMgr::DK_Error, Msg);
 }
 
+// This method takes a RecordVal and uses the source location
+// stored in it.
+void PrintError(const RecordVal *RecVal, const Twine &Msg) {
+  PrintMessage(RecVal->getLoc(), SourceMgr::DK_Error, Msg);
+}
+
 // Functions to print fatal errors.
 
 void PrintFatalError(const Twine &Msg) {

diff  --git a/llvm/lib/TableGen/JSONBackend.cpp b/llvm/lib/TableGen/JSONBackend.cpp
index 196644cda667..ea82934e5d3b 100644
--- a/llvm/lib/TableGen/JSONBackend.cpp
+++ b/llvm/lib/TableGen/JSONBackend.cpp
@@ -59,8 +59,6 @@ json::Value JSONEmitter::translateInit(const Init &I) {
     return Int->getValue();
   } else if (auto *Str = dyn_cast<StringInit>(&I)) {
     return Str->getValue();
-  } else if (auto *Code = dyn_cast<CodeInit>(&I)) {
-    return Code->getValue();
   } else if (auto *List = dyn_cast<ListInit>(&I)) {
     json::Array array;
     for (auto val : *List)

diff  --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index a8f0e19a2bbd..1e2d75f3fe8d 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -43,15 +43,11 @@ using namespace llvm;
 
 static BumpPtrAllocator Allocator;
 
-STATISTIC(CodeInitsConstructed,
-          "The total number of unique CodeInits constructed");
-
 //===----------------------------------------------------------------------===//
 //    Type implementations
 //===----------------------------------------------------------------------===//
 
 BitRecTy BitRecTy::Shared;
-CodeRecTy CodeRecTy::Shared;
 IntRecTy IntRecTy::Shared;
 StringRecTy StringRecTy::Shared;
 DagRecTy DagRecTy::Shared;
@@ -113,18 +109,13 @@ bool IntRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
   return kind==BitRecTyKind || kind==BitsRecTyKind || kind==IntRecTyKind;
 }
 
-bool CodeRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
-  RecTyKind Kind = RHS->getRecTyKind();
-  return Kind == CodeRecTyKind || Kind == StringRecTyKind;
-}
-
 std::string StringRecTy::getAsString() const {
   return "string";
 }
 
 bool StringRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
   RecTyKind Kind = RHS->getRecTyKind();
-  return Kind == StringRecTyKind || Kind == CodeRecTyKind;
+  return Kind == StringRecTyKind;
 }
 
 std::string ListRecTy::getAsString() const {
@@ -514,38 +505,26 @@ IntInit::convertInitializerBitRange(ArrayRef<unsigned> Bits) const {
   return BitsInit::get(NewBits);
 }
 
-CodeInit *CodeInit::get(StringRef V) {
-  static StringMap<CodeInit*, BumpPtrAllocator &> ThePool(Allocator);
+StringInit *StringInit::get(StringRef V, StringFormat Fmt) {
+  static StringMap<StringInit*, BumpPtrAllocator &> StringPool(Allocator);
+  static StringMap<StringInit*, BumpPtrAllocator &> CodePool(Allocator);
 
-  auto &Entry = *ThePool.insert(std::make_pair(V, nullptr)).first;
-  if (!Entry.second)
-    Entry.second = new(Allocator) CodeInit(Entry.getKey());
-  return Entry.second;
-}
-
-StringInit *StringInit::get(StringRef V) {
-  static StringMap<StringInit*, BumpPtrAllocator &> ThePool(Allocator);
-
-  auto &Entry = *ThePool.insert(std::make_pair(V, nullptr)).first;
-  if (!Entry.second)
-    Entry.second = new(Allocator) StringInit(Entry.getKey());
-  return Entry.second;
+  if (Fmt == SF_String) {
+    auto &Entry = *StringPool.insert(std::make_pair(V, nullptr)).first;
+    if (!Entry.second)
+      Entry.second = new (Allocator) StringInit(Entry.getKey(), Fmt);
+    return Entry.second;
+  } else {
+    auto &Entry = *CodePool.insert(std::make_pair(V, nullptr)).first;
+    if (!Entry.second)
+      Entry.second = new (Allocator) StringInit(Entry.getKey(), Fmt);
+    return Entry.second;
+  }
 }
 
 Init *StringInit::convertInitializerTo(RecTy *Ty) const {
   if (isa<StringRecTy>(Ty))
     return const_cast<StringInit *>(this);
-  if (isa<CodeRecTy>(Ty))
-    return CodeInit::get(getValue());
-
-  return nullptr;
-}
-
-Init *CodeInit::convertInitializerTo(RecTy *Ty) const {
-  if (isa<CodeRecTy>(Ty))
-    return const_cast<CodeInit *>(this);
-  if (isa<StringRecTy>(Ty))
-    return StringInit::get(getValue());
 
   return nullptr;
 }
@@ -868,7 +847,9 @@ static StringInit *ConcatStringInits(const StringInit *I0,
                                      const StringInit *I1) {
   SmallString<80> Concat(I0->getValue());
   Concat.append(I1->getValue());
-  return StringInit::get(Concat);
+  return StringInit::get(Concat, 
+                         StringInit::determineFormat(I0->getFormat(),
+                                                     I1->getFormat()));
 }
 
 static StringInit *interleaveStringList(const ListInit *List,
@@ -876,12 +857,15 @@ static StringInit *interleaveStringList(const ListInit *List,
   if (List->size() == 0)
     return StringInit::get("");
   SmallString<80> Result(dyn_cast<StringInit>(List->getElement(0))->getValue());
+  StringInit::StringFormat Fmt = StringInit::SF_String;
   
   for (unsigned I = 1, E = List->size(); I < E; ++I) {
     Result.append(Delim->getValue());
-    Result.append(dyn_cast<StringInit>(List->getElement(I))->getValue());
+    auto *StrInit = dyn_cast<StringInit>(List->getElement(I));
+    Result.append(StrInit->getValue());
+    Fmt = StringInit::determineFormat(Fmt, StrInit->getFormat());
   }
-  return StringInit::get(Result);
+  return StringInit::get(Result, Fmt);
 }
 
 static StringInit *interleaveIntList(const ListInit *List,
@@ -2139,6 +2123,21 @@ StringRef RecordVal::getName() const {
   return cast<StringInit>(getNameInit())->getValue();
 }
 
+std::string RecordVal::getPrintType() const {
+  if (getType() == StringRecTy::get()) {
+    if (auto *StrInit = dyn_cast<StringInit>(Value)) {
+      if (StrInit->hasCodeFormat())
+        return "code";
+      else
+        return "string";
+    } else {
+      return "string";
+    }
+  } else {
+    return TyAndPrefix.getPointer()->getAsString();
+  }
+}
+
 bool RecordVal::setValue(Init *V) {
   if (V) {
     Value = V->getCastTo(getType());
@@ -2193,7 +2192,7 @@ LLVM_DUMP_METHOD void RecordVal::dump() const { errs() << *this; }
 
 void RecordVal::print(raw_ostream &OS, bool PrintSem) const {
   if (getPrefix()) OS << "field ";
-  OS << *getType() << " " << getNameInitAsString();
+  OS << getPrintType() << " " << getNameInitAsString();
 
   if (getValue())
     OS << " = " << *getValue();
@@ -2365,6 +2364,7 @@ StringRef Record::getValueAsString(StringRef FieldName) const {
       "' does not have a field named `" + FieldName + "'!\n");
   return S.getValue();
 }
+
 llvm::Optional<StringRef>
 Record::getValueAsOptionalString(StringRef FieldName) const {
   const RecordVal *R = getValue(FieldName);
@@ -2375,28 +2375,11 @@ Record::getValueAsOptionalString(StringRef FieldName) const {
 
   if (StringInit *SI = dyn_cast<StringInit>(R->getValue()))
     return SI->getValue();
-  if (CodeInit *CI = dyn_cast<CodeInit>(R->getValue()))
-    return CI->getValue();
 
   PrintFatalError(getLoc(),
                   "Record `" + getName() + "', ` field `" + FieldName +
                       "' exists but does not have a string initializer!");
 }
-llvm::Optional<StringRef>
-Record::getValueAsOptionalCode(StringRef FieldName) const {
-  const RecordVal *R = getValue(FieldName);
-  if (!R || !R->getValue())
-    return llvm::Optional<StringRef>();
-  if (isa<UnsetInit>(R->getValue()))
-    return llvm::Optional<StringRef>();
-
-  if (CodeInit *CI = dyn_cast<CodeInit>(R->getValue()))
-    return CI->getValue();
-
-  PrintFatalError(getLoc(),
-                  "Record `" + getName() + "', field `" + FieldName +
-                      "' exists but does not have a code initializer!");
-}
 
 BitsInit *Record::getValueAsBitsInit(StringRef FieldName) const {
   const RecordVal *R = getValue(FieldName);
@@ -2473,8 +2456,6 @@ Record::getValueAsListOfStrings(StringRef FieldName) const {
   for (Init *I : List->getValues()) {
     if (StringInit *SI = dyn_cast<StringInit>(I))
       Strings.push_back(SI->getValue());
-    else if (CodeInit *CI = dyn_cast<CodeInit>(I))
-      Strings.push_back(CI->getValue());
     else
       PrintFatalError(getLoc(),
                       Twine("Record `") + getName() + "', field `" + FieldName +

diff  --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp
index a54161c62d99..df0df96f40eb 100644
--- a/llvm/lib/TableGen/TGLexer.cpp
+++ b/llvm/lib/TableGen/TGLexer.cpp
@@ -540,7 +540,7 @@ tgtok::TokKind TGLexer::LexBracket() {
     }
   }
 
-  return ReturnError(CodeStart-2, "Unterminated Code Block");
+  return ReturnError(CodeStart - 2, "Unterminated code block");
 }
 
 /// LexExclaim - Lex '!' and '![a-zA-Z]+'.

diff  --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h
index 607f428c96d8..1856bef3ea9b 100644
--- a/llvm/lib/TableGen/TGLexer.h
+++ b/llvm/lib/TableGen/TGLexer.h
@@ -86,8 +86,8 @@ class TGLexer {
   // Information about the current token.
   const char *TokStart = nullptr;
   tgtok::TokKind CurCode = tgtok::TokKind::Eof;
-  std::string CurStrVal;  // This is valid for ID, STRVAL, VARNAME, CODEFRAGMENT
-  int64_t CurIntVal = 0;  // This is valid for INTVAL.
+  std::string CurStrVal; // This is valid for Id, StrVal, VarName, CodeFragment
+  int64_t CurIntVal = 0; // This is valid for IntVal.
 
   /// CurBuffer - This is the current buffer index we're lexing from as managed
   /// by the SourceMgr object.

diff  --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 5c9cba5bc926..2671d29a7272 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -799,8 +799,8 @@ bool TGParser::ParseOptionalBitList(SmallVectorImpl<unsigned> &Ranges) {
 RecTy *TGParser::ParseType() {
   switch (Lex.getCode()) {
   default: TokError("Unknown token when expecting a type"); return nullptr;
-  case tgtok::String: Lex.Lex(); return StringRecTy::get();
-  case tgtok::Code:   Lex.Lex(); return CodeRecTy::get();
+  case tgtok::String:
+  case tgtok::Code:   Lex.Lex(); return StringRecTy::get();
   case tgtok::Bit:    Lex.Lex(); return BitRecTy::get();
   case tgtok::Int:    Lex.Lex(); return IntRecTy::get();
   case tgtok::Dag:    Lex.Lex(); return DagRecTy::get();
@@ -1637,6 +1637,9 @@ RecTy *TGParser::ParseOperatorType() {
     return nullptr;
   }
 
+  if (Lex.getCode() == tgtok::Code)
+    TokError("the 'code' type is not allowed in bang operators; use 'string'");
+
   Type = ParseType();
 
   if (!Type) {
@@ -1920,7 +1923,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
     break;
   }
   case tgtok::CodeFragment:
-    R = CodeInit::get(Lex.getCurStrVal());
+    R = StringInit::get(Lex.getCurStrVal(), StringInit::SF_Code);
     Lex.Lex();
     break;
   case tgtok::question:

diff  --git a/llvm/lib/Target/AMDGPU/MIMGInstructions.td b/llvm/lib/Target/AMDGPU/MIMGInstructions.td
index 892c6dd7bd78..7baa6823d16a 100644
--- a/llvm/lib/Target/AMDGPU/MIMGInstructions.td
+++ b/llvm/lib/Target/AMDGPU/MIMGInstructions.td
@@ -51,7 +51,7 @@ def MIMGBaseOpcodesTable : GenericTable {
   let Fields = ["BaseOpcode", "Store", "Atomic", "AtomicX2", "Sampler",
                 "Gather4", "NumExtraArgs", "Gradients", "G16", "Coordinates",
                 "LodOrClampOrMip", "HasD16"];
-  GenericEnum TypeOf_BaseOpcode = MIMGBaseOpcode;
+  string TypeOf_BaseOpcode = "MIMGBaseOpcode";
 
   let PrimaryKey = ["BaseOpcode"];
   let PrimaryKeyName = "getMIMGBaseOpcodeInfo";
@@ -65,7 +65,7 @@ def MIMGDimInfoTable : GenericTable {
   let FilterClass = "AMDGPUDimProps";
   let CppTypeName = "MIMGDimInfo";
   let Fields = ["Dim", "NumCoords", "NumGradients", "DA", "Encoding", "AsmSuffix"];
-  GenericEnum TypeOf_Dim = MIMGDim;
+  string TypeOf_Dim = "MIMGDim";
 
   let PrimaryKey = ["Dim"];
   let PrimaryKeyName = "getMIMGDimInfo";
@@ -95,8 +95,8 @@ def MIMGLZMappingTable : GenericTable {
   let FilterClass = "MIMGLZMapping";
   let CppTypeName = "MIMGLZMappingInfo";
   let Fields = ["L", "LZ"];
-  GenericEnum TypeOf_L = MIMGBaseOpcode;
-  GenericEnum TypeOf_LZ = MIMGBaseOpcode;
+  string TypeOf_L = "MIMGBaseOpcode";
+  string TypeOf_LZ = "MIMGBaseOpcode";
 
   let PrimaryKey = ["L"];
   let PrimaryKeyName = "getMIMGLZMappingInfo";
@@ -111,8 +111,8 @@ def MIMGMIPMappingTable : GenericTable {
   let FilterClass = "MIMGMIPMapping";
   let CppTypeName = "MIMGMIPMappingInfo";
   let Fields = ["MIP", "NONMIP"];
-  GenericEnum TypeOf_MIP = MIMGBaseOpcode;
-  GenericEnum TypeOf_NONMIP = MIMGBaseOpcode;
+  string TypeOf_MIP = "MIMGBaseOpcode";
+  string TypeOf_NONMIP = "MIMGBaseOpcode";
 
   let PrimaryKey = ["MIP"];
   let PrimaryKeyName = "getMIMGMIPMappingInfo";
@@ -127,8 +127,8 @@ def MIMGG16MappingTable : GenericTable {
   let FilterClass = "MIMGG16Mapping";
   let CppTypeName = "MIMGG16MappingInfo";
   let Fields = ["G", "G16"];
-  GenericEnum TypeOf_G = MIMGBaseOpcode;
-  GenericEnum TypeOf_G16 = MIMGBaseOpcode;
+  string TypeOf_G = "MIMGBaseOpcode";
+  string TypeOf_G16 = "MIMGBaseOpcode";
 
   let PrimaryKey = ["G"];
   let PrimaryKeyName = "getMIMGG16MappingInfo";
@@ -168,8 +168,8 @@ def MIMGInfoTable : GenericTable {
   let FilterClass = "MIMG";
   let CppTypeName = "MIMGInfo";
   let Fields = ["Opcode", "BaseOpcode", "MIMGEncoding", "VDataDwords", "VAddrDwords"];
-  GenericEnum TypeOf_BaseOpcode = MIMGBaseOpcode;
-  GenericEnum TypeOf_MIMGEncoding = MIMGEncoding;
+  string TypeOf_BaseOpcode = "MIMGBaseOpcode";
+  string TypeOf_MIMGEncoding = "MIMGEncoding";
 
   let PrimaryKey = ["BaseOpcode", "MIMGEncoding", "VDataDwords", "VAddrDwords"];
   let PrimaryKeyName = "getMIMGOpcodeHelper";
@@ -926,8 +926,8 @@ def ImageDimIntrinsicTable : GenericTable {
     "DMaskIndex", "VAddrStart", "GradientStart", "CoordStart", "LodIndex", "MipIndex", "VAddrEnd",
     "RsrcIndex", "SampIndex", "UnormIndex", "TexFailCtrlIndex", "CachePolicyIndex",
     "GradientTyArg", "CoordTyArg"];
-  GenericEnum TypeOf_BaseOpcode = MIMGBaseOpcode;
-  GenericEnum TypeOf_Dim = MIMGDim;
+  string TypeOf_BaseOpcode = "MIMGBaseOpcode";
+  string TypeOf_Dim = "MIMGDim";
 
   let PrimaryKey = ["Intr"];
   let PrimaryKeyName = "getImageDimIntrinsicInfo";

diff  --git a/llvm/test/TableGen/code.td b/llvm/test/TableGen/code.td
index 317e3e4d3f05..d709b18855bc 100644
--- a/llvm/test/TableGen/code.td
+++ b/llvm/test/TableGen/code.td
@@ -1,22 +1,49 @@
 // RUN: llvm-tblgen %s | FileCheck %s
+// RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
 // XFAIL: vg_leak
 
-// CHECK: --- Defs ---
+// CHECK: def A1
+// CHECK:   code CodeCode = [{code here;}]
+// CHECK:   code StringCode = [{code here;}]
 
-// CHECK: def A0 {
-// CHECK:   code Code = [{Simple}];
-// CHECK: }
+// CHECK: def A2
+// CHECK:   string CodeCode = "string here"
+// CHECK:   string StringCode = "string here"
 
-// CHECK: def B0 {
-// CHECK:   code Code = [{With paste 7}];
-// CHECK: }
+// CHECK: def B1
+// CHECK:   string CodeCode = "with paste 7"
+// CHECK:   string StringCode = "with paste 7"
+
+// CHECK: def C1
+// CHECK:   code CodeCode = [{with concat 42}]
+// CHECK:   code StringCode = [{with concat 42}]
+
+// CHECK: def D1
+// CHECK:   code CodeCode = [{with concat 108!}]
+// CHECK:   code StringCode = [{with concat 108!}]
 
 class A<code c> {
-  code Code = c;
+  code CodeCode = c;
+  string StringCode = c;
 }
 
-def A0 : A<"Simple">;
+def A1 : A<[{code here;}]>;
+def A2 : A<"string here">;
+
+class B<int i> : A<"with paste " # i>;
+class C<int i> : A<!strconcat([{with concat }], !cast<string>(i))>;
+class D<int i> : A<!strconcat([{with concat }], !cast<string>(i), "!")>;
+
+def B1 : B<7>;
+def C1 : C<42>;
+def D1 : D<108>;
 
-class B<int i> : A<"With paste " # i>;
+#ifdef ERROR1
+
+// ERROR1: the 'code' type is not allowed
+
+def Zerror1 {
+  code Code = !cast<code>("i = 0;");
+}
 
-def B0 : B<7>;
+#endif

diff  --git a/llvm/test/TableGen/generic-tables.td b/llvm/test/TableGen/generic-tables.td
index fefa82684294..e410159e6dfb 100644
--- a/llvm/test/TableGen/generic-tables.td
+++ b/llvm/test/TableGen/generic-tables.td
@@ -55,19 +55,26 @@ def ATable : GenericTable {
 
 
 // CHECK-LABEL: GET_BTable_IMPL
+// CHECK: constexpr BTypeName BTable[] = {
+// CHECK:   { "BAlice", 0xAC,  },
+// CHECK:   { "BBob", 0x14, Bob == 13 },
+// CHECK:   { "BCharlie", 0x80, Charlie == 42 },
+// CHECK:   { "BEve", 0x4C, Eve == 108 },
+// CHECK:  };
 // CHECK: const BTypeName *lookupBTableByName(StringRef Name) {
 // CHECK:   return &BTable[Idx->_index];
 // CHECK: }
 
-class BEntry<bits<16> enc> {
+class BEntry<bits<16> enc, code test = [{}]> {
   string Name = NAME;
   bits<16> Encoding = enc;
+  code Test = test;
 }
 
 def BAlice   : BEntry<0xac>;
-def BBob     : BEntry<0x14>;
-def BCharlie : BEntry<0x80>;
-def BEve     : BEntry<0x4c>;
+def BBob     : BEntry<0x14, [{Bob == 13}]>;
+def BCharlie : BEntry<0x80, "Charlie == 42">;
+def BEve     : BEntry<0x4c, [{Eve == }] # 108>;
 
 def BValues : GenericEnum {
   let FilterClass = "BEntry";
@@ -78,7 +85,8 @@ def BValues : GenericEnum {
 def BTable : GenericTable {
   let FilterClass = "BEntry";
   string CppTypeName = "BTypeName";
-  let Fields = ["Name", "Encoding"];
+  let Fields = ["Name", "Encoding", "Test"];
+  string TypeOf_Test = "code";
 }
 
 def lookupBTableByName : SearchIndex {
@@ -126,7 +134,7 @@ def CTable : GenericTable {
   let FilterClass = "CEntry";
   let Fields = ["Name", "Kind", "Encoding"];
 
-  GenericEnum TypeOf_Kind = CEnum;
+  string TypeOf_Kind = "CEnum";
 
   let PrimaryKey = ["Encoding"];
   let PrimaryKeyName = "lookupCEntryByEncoding";

diff  --git a/llvm/test/TableGen/interleave.td b/llvm/test/TableGen/interleave.td
index 7d6bfee15a56..098542ab29a1 100644
--- a/llvm/test/TableGen/interleave.td
+++ b/llvm/test/TableGen/interleave.td
@@ -28,9 +28,9 @@ def Rec1 {
 }
 
 // CHECK: def Rec2
-// CHECK: Test1 = "01234567";
-// CHECK: Test2 = "0, 1, 2, 3, 4, 5, 6, 7";
-// CHECK: Test3 = "0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 42";
+// CHECK:   Test1 = "01234567";
+// CHECK:   Test2 = "0, 1, 2, 3, 4, 5, 6, 7";
+// CHECK:   Test3 = "0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 42";
 
 def Rec2 {
   string Test1 = !interleave(IntList, "");
@@ -39,9 +39,9 @@ def Rec2 {
 }
 
 // CHECK: def Rec3
-// CHECK: Test1 = "271";
-// CHECK: Test2 = "2, 7, 1";
-// CHECK: Test3 = "2 & 7 & 1 & 0";
+// CHECK:   Test1 = "271";
+// CHECK:   Test2 = "2, 7, 1";
+// CHECK:   Test3 = "2 & 7 & 1 & 0";
 
 def Rec3 {
   string Test1 = !interleave(BitsList, "");
@@ -50,9 +50,9 @@ def Rec3 {
 }
 
 // CHECK: def Rec4
-// CHECK: Test1 = "01101";
-// CHECK: Test2 = "0, 1, 1, 0, 1";
-// CHECK: Test3 = "0 and 1 and 1 and 0 and 1 and 1";
+// CHECK:   Test1 = "01101";
+// CHECK:   Test2 = "0, 1, 1, 0, 1";
+// CHECK:   Test3 = "0 and 1 and 1 and 0 and 1 and 1";
 
 def Rec4 {
   string Test1 = !interleave(BitList, "");
@@ -61,14 +61,23 @@ def Rec4 {
 }
 
 // CHECK: def Rec5
-// CHECK: Colors = ["red", "green", "yellow"];
-// CHECK: ColorList = "redify, greenify, yellowify";
+// CHECK:   Colors = ["red", "green", "yellow"];
+// CHECK:   ColorList = "redify, greenify, yellowify";
 
 def Rec5 {
   list<string> Colors = ["red", "green", "yellow"];
   string ColorList = !interleave(Ishify<Colors>.ret, ", ");
 }
 
+// CHECK: def Rec6
+// CHECK:   code OperatorList = [{+, -, *, /, ?:, ;}];
+
+def Rec6 {
+  list<string> Operators = ["+", "-", "*", "/", "?:"];
+  code OperatorList = !interleave(!listconcat(Operators, [[{;}]]), ", ");
+}
+
+
 #ifdef ERROR1
 def op;
 

diff  --git a/llvm/test/TableGen/unterminated-code-block.td b/llvm/test/TableGen/unterminated-code-block.td
index 86395abd789e..d6b6f50827a6 100644
--- a/llvm/test/TableGen/unterminated-code-block.td
+++ b/llvm/test/TableGen/unterminated-code-block.td
@@ -1,5 +1,5 @@
 // RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s
 
-// CHECK: error: Unterminated Code Block
+// CHECK: error: Unterminated code block
 
 include "unterminated-code-block-include.inc" }]>;

diff  --git a/llvm/utils/TableGen/AsmWriterEmitter.cpp b/llvm/utils/TableGen/AsmWriterEmitter.cpp
index f903be169476..9a5908827b4e 100644
--- a/llvm/utils/TableGen/AsmWriterEmitter.cpp
+++ b/llvm/utils/TableGen/AsmWriterEmitter.cpp
@@ -1265,13 +1265,10 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
       << "    break;\n";
 
     for (unsigned i = 0; i < MCOpPredicates.size(); ++i) {
-      Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate");
-      if (CodeInit *SI = dyn_cast<CodeInit>(MCOpPred)) {
-        O << "  case " << i + 1 << ": {\n"
-          << SI->getValue() << "\n"
-          << "    }\n";
-      } else
-        llvm_unreachable("Unexpected MCOperandPredicate field!");
+      StringRef MCOpPred = MCOpPredicates[i]->getValueAsString("MCOperandPredicate");
+      O << "  case " << i + 1 << ": {\n"
+        << MCOpPred.data() << "\n"
+        << "    }\n";
     }
     O << "  }\n"
       << "}\n\n";

diff  --git a/llvm/utils/TableGen/DFAEmitter.cpp b/llvm/utils/TableGen/DFAEmitter.cpp
index e87765085289..781cb0636fa1 100644
--- a/llvm/utils/TableGen/DFAEmitter.cpp
+++ b/llvm/utils/TableGen/DFAEmitter.cpp
@@ -346,8 +346,7 @@ Transition::Transition(Record *R, Automaton *Parent) {
     } else if (isa<IntRecTy>(SymbolV->getType())) {
       Actions.emplace_back(nullptr, R->getValueAsInt(A), "");
       Types.emplace_back("unsigned");
-    } else if (isa<StringRecTy>(SymbolV->getType()) ||
-               isa<CodeRecTy>(SymbolV->getType())) {
+    } else if (isa<StringRecTy>(SymbolV->getType())) {
       Actions.emplace_back(nullptr, 0, std::string(R->getValueAsString(A)));
       Types.emplace_back("std::string");
     } else {

diff  --git a/llvm/utils/TableGen/GICombinerEmitter.cpp b/llvm/utils/TableGen/GICombinerEmitter.cpp
index d84d049e89f0..5f091467636d 100644
--- a/llvm/utils/TableGen/GICombinerEmitter.cpp
+++ b/llvm/utils/TableGen/GICombinerEmitter.cpp
@@ -150,7 +150,7 @@ class CombineRule {
 
   /// A block of arbitrary C++ to finish testing the match.
   /// FIXME: This is a temporary measure until we have actual pattern matching
-  const CodeInit *MatchingFixupCode = nullptr;
+  const StringInit *MatchingFixupCode = nullptr;
 
   /// The MatchData defined by the match stage and required by the apply stage.
   /// This allows the plumbing of arbitrary data from C++ predicates between the
@@ -199,7 +199,7 @@ class CombineRule {
   unsigned allocUID() { return UID++; }
   StringRef getName() const { return TheDef.getName(); }
   const Record &getDef() const { return TheDef; }
-  const CodeInit *getMatchingFixupCode() const { return MatchingFixupCode; }
+  const StringInit *getMatchingFixupCode() const { return MatchingFixupCode; }
   size_t getNumRoots() const { return Roots.size(); }
 
   GIMatchDag &getMatchDag() { return MatchDag; }
@@ -514,10 +514,10 @@ bool CombineRule::parseMatcher(const CodeGenTarget &Target) {
 
 
     // Parse arbitrary C++ code we have in lieu of supporting MIR matching
-    if (const CodeInit *CodeI = dyn_cast<CodeInit>(Matchers->getArg(I))) {
+    if (const StringInit *StringI = dyn_cast<StringInit>(Matchers->getArg(I))) {
       assert(!MatchingFixupCode &&
              "Only one block of arbitrary code is currently permitted");
-      MatchingFixupCode = CodeI;
+      MatchingFixupCode = StringI;
       MatchDag.setHasPostMatchPredicate(true);
       continue;
     }
@@ -807,7 +807,7 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS,
     }
     OS << ") {\n" << Indent << "   ";
 
-    if (const CodeInit *Code = dyn_cast<CodeInit>(Applyer->getArg(0))) {
+    if (const StringInit *Code = dyn_cast<StringInit>(Applyer->getArg(0))) {
       OS << CodeExpander(Code->getAsUnquotedString(), Expansions,
                          RuleDef.getLoc(), ShowExpansions)
          << "\n"

diff  --git a/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp b/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp
index 200644213ca1..dcca207be7c1 100644
--- a/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp
+++ b/llvm/utils/TableGen/RISCVCompressInstEmitter.cpp
@@ -533,14 +533,11 @@ static unsigned getPredicates(DenseMap<const Record *, unsigned> &PredicateMap,
 static void printPredicates(std::vector<const Record *> &Predicates,
                             StringRef Name, raw_ostream &o) {
   for (unsigned i = 0; i < Predicates.size(); ++i) {
-    Init *Pred = Predicates[i]->getValueInit(Name);
-    if (CodeInit *SI = dyn_cast<CodeInit>(Pred))
-      o << "  case " << i + 1 << ": {\n"
-        << "  // " << Predicates[i]->getName().str() << "\n"
-        << "  " << SI->getValue() << "\n"
-        << "  }\n";
-    else
-      llvm_unreachable("Unexpected predicate field!");
+    StringRef Pred = Predicates[i]->getValueAsString(Name);
+    o << "  case " << i + 1 << ": {\n"
+      << "  // " << Predicates[i]->getName().str() << "\n"
+      << "  " << Pred.data() << "\n"
+      << "  }\n";
   }
 }
 

diff  --git a/llvm/utils/TableGen/SearchableTableEmitter.cpp b/llvm/utils/TableGen/SearchableTableEmitter.cpp
index 3c292f30dbcf..2e86b137ac58 100644
--- a/llvm/utils/TableGen/SearchableTableEmitter.cpp
+++ b/llvm/utils/TableGen/SearchableTableEmitter.cpp
@@ -54,6 +54,7 @@ struct GenericEnum {
 struct GenericField {
   std::string Name;
   RecTy *RecType = nullptr;
+  bool IsCode = false;
   bool IsIntrinsic = false;
   bool IsInstruction = false;
   GenericEnum *Enum = nullptr;
@@ -111,14 +112,15 @@ class SearchableTableEmitter {
 
   std::string primaryRepresentation(SMLoc Loc, const GenericField &Field,
                                     Init *I) {
-    if (StringInit *SI = dyn_cast<StringInit>(I))
-      return SI->getAsString();
-    else if (BitsInit *BI = dyn_cast<BitsInit>(I))
+    if (StringInit *SI = dyn_cast<StringInit>(I)) {
+      if (Field.IsCode || SI->hasCodeFormat())
+        return std::string(SI->getValue());
+      else
+        return SI->getAsString();
+    } else if (BitsInit *BI = dyn_cast<BitsInit>(I))
       return "0x" + utohexstr(getAsInt(BI));
     else if (BitInit *BI = dyn_cast<BitInit>(I))
       return BI->getValue() ? "true" : "false";
-    else if (CodeInit *CI = dyn_cast<CodeInit>(I))
-      return std::string(CI->getValue());
     else if (Field.IsIntrinsic)
       return "Intrinsic::" + getIntrinsic(I).EnumName;
     else if (Field.IsInstruction)
@@ -150,10 +152,6 @@ class SearchableTableEmitter {
 
   bool compareBy(Record *LHS, Record *RHS, const SearchIndex &Index);
 
-  bool isIntegral(Init *I) {
-    return isa<BitsInit>(I) || isa<CodeInit>(I) || isIntrinsic(I);
-  }
-
   std::string searchableFieldType(const GenericTable &Table,
                                   const SearchIndex &Index,
                                   const GenericField &Field, TypeContext Ctx) {
@@ -545,13 +543,19 @@ void SearchableTableEmitter::emitGenericTable(const GenericTable &Table,
   OS << "#endif\n\n";
 }
 
-bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *II) {
-  if (auto DI = dyn_cast<DefInit>(II)) {
-    Record *TypeRec = DI->getDef();
-    if (TypeRec->isSubClassOf("GenericEnum")) {
-      Field.Enum = EnumMap[TypeRec];
-      Field.RecType = RecordRecTy::get(Field.Enum->Class);
+bool SearchableTableEmitter::parseFieldType(GenericField &Field, Init *TypeOf) {
+  if (auto Type = dyn_cast<StringInit>(TypeOf)) {
+    if (Type->getValue() == "code") {
+      Field.IsCode = true;
       return true;
+    } else {
+      if (Record *TypeRec = Records.getDef(Type->getValue())) {
+        if (TypeRec->isSubClassOf("GenericEnum")) {
+          Field.Enum = EnumMap[TypeRec];
+          Field.RecType = RecordRecTy::get(Field.Enum->Class);
+          return true;
+        }
+      }
     }
   }
 
@@ -708,12 +712,14 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
     for (const auto &FieldName : Fields) {
       Table->Fields.emplace_back(FieldName); // Construct a GenericField.
 
-      if (auto TypeOfVal = TableRec->getValue(("TypeOf_" + FieldName).str())) {
-        if (!parseFieldType(Table->Fields.back(), TypeOfVal->getValue())) {
-          PrintFatalError(TypeOfVal, 
-                          Twine("Table '") + Table->Name +
-                              "' has invalid 'TypeOf_" + FieldName +
-                              "': " + TypeOfVal->getValue()->getAsString());
+      if (auto TypeOfRecordVal = TableRec->getValue(("TypeOf_" + FieldName).str())) {
+        if (!parseFieldType(Table->Fields.back(), TypeOfRecordVal->getValue())) {
+          PrintError(TypeOfRecordVal, 
+                     Twine("Table '") + Table->Name +
+                         "' has invalid 'TypeOf_" + FieldName +
+                         "': " + TypeOfRecordVal->getValue()->getAsString());
+          PrintFatalNote("The 'TypeOf_xxx' field must be a string naming a "
+                         "GenericEnum record, or \"code\"");
         }
       }
     }

diff  --git a/mlir/include/mlir/TableGen/Operator.h b/mlir/include/mlir/TableGen/Operator.h
index d7fac87af0be..16d154b3beb0 100644
--- a/mlir/include/mlir/TableGen/Operator.h
+++ b/mlir/include/mlir/TableGen/Operator.h
@@ -28,7 +28,6 @@
 #include "llvm/Support/SMLoc.h"
 
 namespace llvm {
-class CodeInit;
 class DefInit;
 class Record;
 class StringInit;

diff  --git a/mlir/lib/TableGen/Attribute.cpp b/mlir/lib/TableGen/Attribute.cpp
index 3377ec98c229..99d9d8ab9b3a 100644
--- a/mlir/lib/TableGen/Attribute.cpp
+++ b/mlir/lib/TableGen/Attribute.cpp
@@ -18,7 +18,6 @@
 using namespace mlir;
 using namespace mlir::tblgen;
 
-using llvm::CodeInit;
 using llvm::DefInit;
 using llvm::Init;
 using llvm::Record;
@@ -27,8 +26,6 @@ using llvm::StringInit;
 // Returns the initializer's value as string if the given TableGen initializer
 // is a code or string initializer. Returns the empty StringRef otherwise.
 static StringRef getValueAsString(const Init *init) {
-  if (const auto *code = dyn_cast<CodeInit>(init))
-    return code->getValue().trim();
   if (const auto *str = dyn_cast<StringInit>(init))
     return str->getValue().trim();
   return {};

diff  --git a/mlir/lib/TableGen/Dialect.cpp b/mlir/lib/TableGen/Dialect.cpp
index c17180c20483..0c1de78ce60e 100644
--- a/mlir/lib/TableGen/Dialect.cpp
+++ b/mlir/lib/TableGen/Dialect.cpp
@@ -38,7 +38,7 @@ std::string Dialect::getCppClassName() const {
 static StringRef getAsStringOrEmpty(const llvm::Record &record,
                                     StringRef fieldName) {
   if (auto valueInit = record.getValueInit(fieldName)) {
-    if (llvm::isa<llvm::CodeInit, llvm::StringInit>(valueInit))
+    if (llvm::isa<llvm::StringInit>(valueInit))
       return record.getValueAsString(fieldName);
   }
   return "";

diff  --git a/mlir/lib/TableGen/Operator.cpp b/mlir/lib/TableGen/Operator.cpp
index b59ffaf8d092..ca1442f547d5 100644
--- a/mlir/lib/TableGen/Operator.cpp
+++ b/mlir/lib/TableGen/Operator.cpp
@@ -547,12 +547,12 @@ StringRef Operator::getSummary() const {
 
 bool Operator::hasAssemblyFormat() const {
   auto *valueInit = def.getValueInit("assemblyFormat");
-  return isa<llvm::CodeInit, llvm::StringInit>(valueInit);
+  return isa<llvm::StringInit>(valueInit);
 }
 
 StringRef Operator::getAssemblyFormat() const {
   return TypeSwitch<llvm::Init *, StringRef>(def.getValueInit("assemblyFormat"))
-      .Case<llvm::StringInit, llvm::CodeInit>(
+      .Case<llvm::StringInit>(
           [&](auto *init) { return init->getValue(); });
 }
 

diff  --git a/mlir/lib/TableGen/Pattern.cpp b/mlir/lib/TableGen/Pattern.cpp
index 4128936d4b7f..0dae7ff71883 100644
--- a/mlir/lib/TableGen/Pattern.cpp
+++ b/mlir/lib/TableGen/Pattern.cpp
@@ -55,7 +55,7 @@ bool DagLeaf::isEnumAttrCase() const {
 }
 
 bool DagLeaf::isStringAttr() const {
-  return isa<llvm::StringInit, llvm::CodeInit>(def);
+  return isa<llvm::StringInit>(def);
 }
 
 Constraint DagLeaf::getAsConstraint() const {

diff  --git a/mlir/lib/TableGen/Type.cpp b/mlir/lib/TableGen/Type.cpp
index a3d6ac6a7e88..5fe6bbbd5e83 100644
--- a/mlir/lib/TableGen/Type.cpp
+++ b/mlir/lib/TableGen/Type.cpp
@@ -46,7 +46,7 @@ Optional<StringRef> TypeConstraint::getBuilderCall() const {
   if (!builderCall || !builderCall->getValue())
     return llvm::None;
   return TypeSwitch<llvm::Init *, Optional<StringRef>>(builderCall->getValue())
-      .Case<llvm::StringInit, llvm::CodeInit>([&](auto *init) {
+      .Case<llvm::StringInit>([&](auto *init) {
         StringRef value = init->getValue();
         return value.empty() ? Optional<StringRef>() : value;
       })

diff  --git a/mlir/lib/TableGen/TypeDef.cpp b/mlir/lib/TableGen/TypeDef.cpp
index aa7f36a3626b..d8412b6b4be5 100644
--- a/mlir/lib/TableGen/TypeDef.cpp
+++ b/mlir/lib/TableGen/TypeDef.cpp
@@ -78,10 +78,10 @@ llvm::Optional<StringRef> TypeDef::getMnemonic() const {
   return def->getValueAsOptionalString("mnemonic");
 }
 llvm::Optional<StringRef> TypeDef::getPrinterCode() const {
-  return def->getValueAsOptionalCode("printer");
+  return def->getValueAsOptionalString("printer");
 }
 llvm::Optional<StringRef> TypeDef::getParserCode() const {
-  return def->getValueAsOptionalCode("parser");
+  return def->getValueAsOptionalString("parser");
 }
 bool TypeDef::genAccessors() const {
   return def->getValueAsBit("genAccessors");
@@ -114,7 +114,7 @@ llvm::Optional<StringRef> TypeParameter::getAllocator() const {
     llvm::RecordVal *code = typeParameter->getDef()->getValue("allocator");
     if (!code)
       return llvm::Optional<StringRef>();
-    if (llvm::CodeInit *ci = dyn_cast<llvm::CodeInit>(code->getValue()))
+    if (llvm::StringInit *ci = dyn_cast<llvm::StringInit>(code->getValue()))
       return ci->getValue();
     if (isa<llvm::UnsetInit>(code->getValue()))
       return llvm::Optional<StringRef>();

diff  --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
index 6ab92c040c16..c96fde648eb2 100644
--- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
@@ -137,7 +137,7 @@ static std::string replaceAllSubstrs(std::string str, const std::string &match,
 static inline bool hasStringAttribute(const Record &record,
                                       StringRef fieldName) {
   auto valueInit = record.getValueInit(fieldName);
-  return isa<CodeInit, StringInit>(valueInit);
+  return isa<StringInit>(valueInit);
 }
 
 static std::string getArgumentName(const Operator &op, int index) {
@@ -1796,15 +1796,15 @@ void OpEmitter::genPrinter() {
     return;
 
   auto valueInit = def.getValueInit("printer");
-  CodeInit *codeInit = dyn_cast<CodeInit>(valueInit);
-  if (!codeInit)
+  StringInit *stringInit = dyn_cast<StringInit>(valueInit);
+  if (!stringInit)
     return;
 
   auto *method =
       opClass.addMethodAndPrune("void", "print", "::mlir::OpAsmPrinter &", "p");
   FmtContext fctx;
   fctx.addSubst("cppClass", opClass.getClassName());
-  auto printer = codeInit->getValue().ltrim().rtrim(" \t\v\f\r");
+  auto printer = stringInit->getValue().ltrim().rtrim(" \t\v\f\r");
   method->body() << "  " << tgfmt(printer, &fctx);
 }
 
@@ -1816,8 +1816,8 @@ void OpEmitter::genVerifier() {
        << "return ::mlir::failure();\n";
 
   auto *valueInit = def.getValueInit("verifier");
-  CodeInit *codeInit = dyn_cast<CodeInit>(valueInit);
-  bool hasCustomVerify = codeInit && !codeInit->getValue().empty();
+  StringInit *stringInit = dyn_cast<StringInit>(valueInit);
+  bool hasCustomVerify = stringInit && !stringInit->getValue().empty();
   populateSubstitutions(op, "this->getAttr", "this->getODSOperands",
                         "this->getODSResults", verifyCtx);
 
@@ -1841,7 +1841,7 @@ void OpEmitter::genVerifier() {
   if (hasCustomVerify) {
     FmtContext fctx;
     fctx.addSubst("cppClass", opClass.getClassName());
-    auto printer = codeInit->getValue().ltrim().rtrim(" \t\v\f\r");
+    auto printer = stringInit->getValue().ltrim().rtrim(" \t\v\f\r");
     body << "  " << tgfmt(printer, &fctx);
   } else {
     body << "  return ::mlir::success();\n";


        


More information about the llvm-branch-commits mailing list