[TableGen] Eliminate the 'code' type

Update the documentation.

Rework various backends that relied on the code type.

Differential Revision: https://reviews.llvm.org/D92269
This commit is contained in:
Paul C. Anagnostopoulos 2020-11-24 13:09:02 -05:00
parent 1365718778
commit 415fab6f67
31 changed files with 279 additions and 286 deletions

View File

@ -217,8 +217,6 @@ std::string getRSTStringWithTextFallback(const Record *R, StringRef Primary,
StringRef Value; StringRef Value;
if (auto *SV = dyn_cast_or_null<StringInit>(V->getValue())) if (auto *SV = dyn_cast_or_null<StringInit>(V->getValue()))
Value = SV->getValue(); Value = SV->getValue();
else if (auto *CV = dyn_cast_or_null<CodeInit>(V->getValue()))
Value = CV->getValue();
if (!Value.empty()) if (!Value.empty())
return Field == Primary ? Value.str() : escapeRST(Value); return Field == Primary ? Value.str() : escapeRST(Value);
} }

View File

@ -693,8 +693,8 @@ This class provides six fields.
table that holds the entries. If unspecified, the ``FilterClass`` name is table that holds the entries. If unspecified, the ``FilterClass`` name is
used. used.
* ``list<string> Fields``. A list of the names of the fields in the * ``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 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 this list determines the order of the values in the C++ initializers. See
below for information about the types of these fields. 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. * ``bit PrimaryKeyEarlyOut``. See the third example below.
TableGen attempts to deduce the type of each of the table fields. It can TableGen attempts to deduce the type of each of the table fields so that it
deduce ``bit``, ``bits<n>``, ``string``, ``Intrinsic``, and ``Instruction``. can format the C++ initializers in the emitted table. It can deduce ``bit``,
These can be used in the primary key. TableGen also deduces ``code``, but it ``bits<n>``, ``string``, ``Intrinsic``, and ``Instruction``. These can be
cannot be used in the primary key. Any other field types must be specified 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 explicitly; this is done as shown in the second example below. Such fields
cannot be used in the primary key. 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 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 table entry records are anonymous; the names of entry records are
irrelevant. irrelevant.
@ -793,7 +806,7 @@ pointer if no entry is found.
This example includes a field whose type TableGen cannot deduce. The ``Kind`` This example includes a field whose type TableGen cannot deduce. The ``Kind``
field uses the enumerated type ``CEnum`` defined above. To inform TableGen 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 named ``TypeOf_``\ *field*, where *field* is the name of the field whose type
is required. is required.
@ -802,7 +815,7 @@ is required.
def CTable : GenericTable { def CTable : GenericTable {
let FilterClass = "CEntry"; let FilterClass = "CEntry";
let Fields = ["Name", "Kind", "Encoding"]; let Fields = ["Name", "Kind", "Encoding"];
GenericEnum TypeOf_Kind = CEnum; string TypeOf_Kind = "CEnum";
let PrimaryKey = ["Encoding"]; let PrimaryKey = ["Encoding"];
let PrimaryKeyName = "lookupCEntryByEncoding"; let PrimaryKeyName = "lookupCEntryByEncoding";
} }

View File

@ -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 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 that represent specific value types (except for the unset value). These
classes include ``BitInit``, ``BitsInit``, ``CodeInit``, ``DagInit``, classes include ``BitInit``, ``BitsInit``, ``DagInit``, ``DefInit``,
``DefInit``, ``IntInit``, ``ListInit``, and ``StringInit``. (There are ``IntInit``, ``ListInit``, and ``StringInit``. (There are additional derived
additional derived types used by the TableGen parser.) types used by the TableGen parser.)
This class includes a data member that specifies the ``RecTy`` type of the This class includes a data member that specifies the ``RecTy`` type of the
value. It provides a function to get that ``RecTy`` type. 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. * 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`` ``DagInit``
~~~~~~~~~~~ ~~~~~~~~~~~

View File

@ -167,10 +167,11 @@ TableGen has two kinds of string literals:
.. productionlist:: .. productionlist::
TokString: '"' (non-'"' characters and escapes) '"' 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 A :token:`TokCode` is nothing more than a multi-line string literal
delimited by ``[{`` and ``}]``. It can break across lines. 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:: 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. wide range of records conveniently and compactly.
.. productionlist:: .. productionlist::
Type: "bit" | "int" | "string" | "code" | "dag" Type: "bit" | "int" | "string" | "dag"
:| "bits" "<" `TokInteger` ">" :| "bits" "<" `TokInteger` ">"
:| "list" "<" `Type` ">" :| "list" "<" `Type` ">"
:| `ClassID` :| `ClassID`
@ -271,11 +272,6 @@ wide range of records conveniently and compactly.
The ``string`` type represents an ordered sequence of characters of arbitrary The ``string`` type represents an ordered sequence of characters of arbitrary
length. 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*\ ``>`` ``bits<``\ *n*\ ``>``
The ``bits`` type is a fixed-sized integer of arbitrary length *n* that The ``bits`` type is a fixed-sized integer of arbitrary length *n* that
is treated as separate bits. These bits can be accessed individually. 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. The :token:`SimpleValue` has a number of forms.
.. productionlist:: .. productionlist::
SimpleValue: `TokInteger` | `TokString`+ | `TokCodeFragment` SimpleValue: `TokInteger` | `TokString`+ | `TokCode`
A value can be an integer literal, a string literal, or a code fragment A value can be an integer literal, a string literal, or a code literal.
literal. Multiple adjacent string literals are concatenated as in C/C++; the Multiple adjacent string literals are concatenated as in C/C++; the simple
simple value is the concatenation of the strings. Code fragments become value is the concatenation of the strings. Code literals become strings and
strings and then are indistinguishable from them. are then indistinguishable from them.
.. productionlist:: .. productionlist::
SimpleValue2: "true" | "false" SimpleValue2: "true" | "false"
@ -616,14 +612,15 @@ name of a multiclass.
.. productionlist:: .. productionlist::
Body: ";" | "{" `BodyItem`* "}" Body: ";" | "{" `BodyItem`* "}"
BodyItem: `Type` `TokIdentifier` ["=" `Value`] ";" BodyItem: (`Type` | "code") `TokIdentifier` ["=" `Value`] ";"
:| "let" `TokIdentifier` ["{" `RangeList` "}"] "=" `Value` ";" :| "let" `TokIdentifier` ["{" `RangeList` "}"] "=" `Value` ";"
:| "defvar" `TokIdentifier` "=" `Value` ";" :| "defvar" `TokIdentifier` "=" `Value` ";"
A field definition in the body specifies a field to be included in the class 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 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 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 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 for fields defined directly in the body or fields inherited from

View File

@ -22,6 +22,7 @@ namespace llvm {
void PrintNote(const Twine &Msg); void PrintNote(const Twine &Msg);
void PrintNote(ArrayRef<SMLoc> NoteLoc, 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, LLVM_ATTRIBUTE_NORETURN void PrintFatalNote(ArrayRef<SMLoc> ErrorLoc,
const Twine &Msg); const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void PrintFatalNote(const Record *Rec, 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(ArrayRef<SMLoc> ErrorLoc, const Twine &Msg);
void PrintError(const char *Loc, const Twine &Msg); void PrintError(const char *Loc, const Twine &Msg);
void PrintError(const Record *Rec, 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(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void PrintFatalError(ArrayRef<SMLoc> ErrorLoc, LLVM_ATTRIBUTE_NORETURN void PrintFatalError(ArrayRef<SMLoc> ErrorLoc,

View File

@ -58,7 +58,6 @@ public:
enum RecTyKind { enum RecTyKind {
BitRecTyKind, BitRecTyKind,
BitsRecTyKind, BitsRecTyKind,
CodeRecTyKind,
IntRecTyKind, IntRecTyKind,
StringRecTyKind, StringRecTyKind,
ListRecTyKind, ListRecTyKind,
@ -138,24 +137,6 @@ public:
bool typeIsA(const RecTy *RHS) const override; 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 /// 'int' - Represent an integer value of no particular size
class IntRecTy : public RecTy { class IntRecTy : public RecTy {
static IntRecTy Shared; static IntRecTy Shared;
@ -306,7 +287,6 @@ protected:
IK_FirstTypedInit, IK_FirstTypedInit,
IK_BitInit, IK_BitInit,
IK_BitsInit, IK_BitsInit,
IK_CodeInit,
IK_DagInit, IK_DagInit,
IK_DefInit, IK_DefInit,
IK_FieldInit, IK_FieldInit,
@ -597,16 +577,18 @@ public:
/// "foo" - Represent an initialization by a string value. /// "foo" - Represent an initialization by a string value.
class StringInit : public TypedInit { class StringInit : public TypedInit {
//// enum StringFormat { public:
//// SF_String, // Format as "text" enum StringFormat {
//// SF_Code, // Format as [{text}] SF_String, // Format as "text"
//// }; SF_Code, // Format as [{text}]
};
private:
StringRef Value; StringRef Value;
//// StringFormat Format; StringFormat Format;
explicit StringInit(StringRef V) explicit StringInit(StringRef V, StringFormat Fmt)
: TypedInit(IK_StringInit, StringRecTy::get()), Value(V) {} : TypedInit(IK_StringInit, StringRecTy::get()), Value(V), Format(Fmt) {}
public: public:
StringInit(const StringInit &) = delete; StringInit(const StringInit &) = delete;
@ -616,47 +598,24 @@ public:
return I->getKind() == IK_StringInit; return I->getKind() == IK_StringInit;
} }
static StringInit *get(StringRef); static StringInit *get(StringRef, StringFormat Fmt = SF_String);
static StringFormat determineFormat(StringFormat Fmt1, StringFormat Fmt2) {
return (Fmt1 == SF_Code || Fmt2 == SF_Code) ? SF_Code : SF_String;
}
StringRef getValue() const { return Value; } StringRef getValue() const { return Value; }
StringFormat getFormat() const { return Format; }
bool hasCodeFormat() const { return Format == SF_Code; }
Init *convertInitializerTo(RecTy *Ty) const override; Init *convertInitializerTo(RecTy *Ty) const override;
bool isConcrete() const override { return true; } 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 CodeInit *get(StringRef);
StringRef getValue() const { return Value; }
Init *convertInitializerTo(RecTy *Ty) const override;
bool isConcrete() const override { return true; }
std::string getAsString() const override { std::string getAsString() const override {
if (Format == SF_String)
return "\"" + Value.str() + "\"";
else
return "[{" + Value.str() + "}]"; return "[{" + Value.str() + "}]";
} }
@ -1438,6 +1397,9 @@ public:
/// Get the type of the field value as a RecTy. /// Get the type of the field value as a RecTy.
RecTy *getType() const { return TyAndPrefix.getPointer(); } 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. /// Get the value of the field as an Init.
Init *getValue() const { return Value; } Init *getValue() const { return Value; }
@ -1675,11 +1637,6 @@ public:
/// not a string and llvm::Optional() if the field does not exist. /// not a string and llvm::Optional() if the field does not exist.
llvm::Optional<StringRef> getValueAsOptionalString(StringRef FieldName) const; 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 /// This method looks up the specified field and returns
/// its value as a BitsInit, throwing an exception if the field does not exist /// its value as a BitsInit, throwing an exception if the field does not exist
/// or if the value is not the right type. /// or if the value is not the right type.

View File

@ -67,9 +67,13 @@ class GenericTable {
// List of the names of fields of collected records that contain the data for // 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++. // 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 // TableGen needs to know the type of the fields so that it can format
// called TypeOf_XXX and use that as a more detailed description of the // the initializers correctly. It can infer the type of bit, bits, string,
// type of the field if present. This is required for fields whose type // 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: // cannot be deduced automatically, such as enum fields. For example:
// //
// def MyEnum : GenericEnum { // def MyEnum : GenericEnum {
@ -85,15 +89,15 @@ class GenericTable {
// def MyTable : GenericTable { // def MyTable : GenericTable {
// let FilterClass = "MyTableEntry"; // let FilterClass = "MyTableEntry";
// let Fields = ["V", ...]; // let Fields = ["V", ...];
// GenericEnum TypeOf_V = MyEnum; // string TypeOf_V = "MyEnum";
// } // }
// //
// Fields of type bit, bits<N>, string, Intrinsic, and Instruction (or // If a string field was initialized with a code literal, TableGen will
// derived classes of those) are supported natively. // 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 // string TypeOf_Predicate = "code";
// verbatim as an initializer. However, these fields cannot be used as
// search keys.
list<string> Fields; list<string> Fields;
// (Optional) List of fields that make up the primary key. // (Optional) List of fields that make up the primary key.

View File

@ -52,6 +52,13 @@ void PrintNote(ArrayRef<SMLoc> NoteLoc, const Twine &Msg) {
// Functions to print fatal notes. // 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) { void PrintFatalNote(ArrayRef<SMLoc> NoteLoc, const Twine &Msg) {
PrintNote(NoteLoc, Msg); PrintNote(NoteLoc, Msg);
// The following call runs the file cleanup handlers. // 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); 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. // Functions to print fatal errors.
void PrintFatalError(const Twine &Msg) { void PrintFatalError(const Twine &Msg) {

View File

@ -59,8 +59,6 @@ json::Value JSONEmitter::translateInit(const Init &I) {
return Int->getValue(); return Int->getValue();
} else if (auto *Str = dyn_cast<StringInit>(&I)) { } else if (auto *Str = dyn_cast<StringInit>(&I)) {
return Str->getValue(); return Str->getValue();
} else if (auto *Code = dyn_cast<CodeInit>(&I)) {
return Code->getValue();
} else if (auto *List = dyn_cast<ListInit>(&I)) { } else if (auto *List = dyn_cast<ListInit>(&I)) {
json::Array array; json::Array array;
for (auto val : *List) for (auto val : *List)

View File

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

View File

@ -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]+'. /// LexExclaim - Lex '!' and '![a-zA-Z]+'.

View File

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

View File

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

View File

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

View File

@ -1,22 +1,49 @@
// RUN: llvm-tblgen %s | FileCheck %s // RUN: llvm-tblgen %s | FileCheck %s
// RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
// XFAIL: vg_leak // XFAIL: vg_leak
// CHECK: --- Defs --- // CHECK: def A1
// CHECK: code CodeCode = [{code here;}]
// CHECK: code StringCode = [{code here;}]
// CHECK: def A0 { // CHECK: def A2
// CHECK: code Code = [{Simple}]; // CHECK: string CodeCode = "string here"
// CHECK: } // CHECK: string StringCode = "string here"
// CHECK: def B0 { // CHECK: def B1
// CHECK: code Code = [{With paste 7}]; // CHECK: string CodeCode = "with paste 7"
// CHECK: } // 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> { 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 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 B0 : B<7>; def B1 : B<7>;
def C1 : C<42>;
def D1 : D<108>;
#ifdef ERROR1
// ERROR1: the 'code' type is not allowed
def Zerror1 {
code Code = !cast<code>("i = 0;");
}
#endif

View File

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

View File

@ -69,6 +69,15 @@ def Rec5 {
string ColorList = !interleave(Ishify<Colors>.ret, ", "); string ColorList = !interleave(Ishify<Colors>.ret, ", ");
} }
// CHECK: def Rec6
// CHECK: code OperatorList = [{+, -, *, /, ?:, ;}];
def Rec6 {
list<string> Operators = ["+", "-", "*", "/", "?:"];
code OperatorList = !interleave(!listconcat(Operators, [[{;}]]), ", ");
}
#ifdef ERROR1 #ifdef ERROR1
def op; def op;

View File

@ -1,5 +1,5 @@
// RUN: not llvm-tblgen -I %p %s 2>&1 | FileCheck %s // 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" }]>; include "unterminated-code-block-include.inc" }]>;

View File

@ -1265,13 +1265,10 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
<< " break;\n"; << " break;\n";
for (unsigned i = 0; i < MCOpPredicates.size(); ++i) { for (unsigned i = 0; i < MCOpPredicates.size(); ++i) {
Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate"); StringRef MCOpPred = MCOpPredicates[i]->getValueAsString("MCOperandPredicate");
if (CodeInit *SI = dyn_cast<CodeInit>(MCOpPred)) {
O << " case " << i + 1 << ": {\n" O << " case " << i + 1 << ": {\n"
<< SI->getValue() << "\n" << MCOpPred.data() << "\n"
<< " }\n"; << " }\n";
} else
llvm_unreachable("Unexpected MCOperandPredicate field!");
} }
O << " }\n" O << " }\n"
<< "}\n\n"; << "}\n\n";

View File

@ -346,8 +346,7 @@ Transition::Transition(Record *R, Automaton *Parent) {
} else if (isa<IntRecTy>(SymbolV->getType())) { } else if (isa<IntRecTy>(SymbolV->getType())) {
Actions.emplace_back(nullptr, R->getValueAsInt(A), ""); Actions.emplace_back(nullptr, R->getValueAsInt(A), "");
Types.emplace_back("unsigned"); Types.emplace_back("unsigned");
} else if (isa<StringRecTy>(SymbolV->getType()) || } else if (isa<StringRecTy>(SymbolV->getType())) {
isa<CodeRecTy>(SymbolV->getType())) {
Actions.emplace_back(nullptr, 0, std::string(R->getValueAsString(A))); Actions.emplace_back(nullptr, 0, std::string(R->getValueAsString(A)));
Types.emplace_back("std::string"); Types.emplace_back("std::string");
} else { } else {

View File

@ -150,7 +150,7 @@ protected:
/// A block of arbitrary C++ to finish testing the match. /// A block of arbitrary C++ to finish testing the match.
/// FIXME: This is a temporary measure until we have actual pattern matching /// 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. /// 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 /// This allows the plumbing of arbitrary data from C++ predicates between the
@ -199,7 +199,7 @@ public:
unsigned allocUID() { return UID++; } unsigned allocUID() { return UID++; }
StringRef getName() const { return TheDef.getName(); } StringRef getName() const { return TheDef.getName(); }
const Record &getDef() const { return TheDef; } 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(); } size_t getNumRoots() const { return Roots.size(); }
GIMatchDag &getMatchDag() { return MatchDag; } 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 // 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 && assert(!MatchingFixupCode &&
"Only one block of arbitrary code is currently permitted"); "Only one block of arbitrary code is currently permitted");
MatchingFixupCode = CodeI; MatchingFixupCode = StringI;
MatchDag.setHasPostMatchPredicate(true); MatchDag.setHasPostMatchPredicate(true);
continue; continue;
} }
@ -807,7 +807,7 @@ void GICombinerEmitter::generateCodeForTree(raw_ostream &OS,
} }
OS << ") {\n" << Indent << " "; 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, OS << CodeExpander(Code->getAsUnquotedString(), Expansions,
RuleDef.getLoc(), ShowExpansions) RuleDef.getLoc(), ShowExpansions)
<< "\n" << "\n"

View File

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

View File

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

View File

@ -28,7 +28,6 @@
#include "llvm/Support/SMLoc.h" #include "llvm/Support/SMLoc.h"
namespace llvm { namespace llvm {
class CodeInit;
class DefInit; class DefInit;
class Record; class Record;
class StringInit; class StringInit;

View File

@ -18,7 +18,6 @@
using namespace mlir; using namespace mlir;
using namespace mlir::tblgen; using namespace mlir::tblgen;
using llvm::CodeInit;
using llvm::DefInit; using llvm::DefInit;
using llvm::Init; using llvm::Init;
using llvm::Record; using llvm::Record;
@ -27,8 +26,6 @@ using llvm::StringInit;
// Returns the initializer's value as string if the given TableGen initializer // Returns the initializer's value as string if the given TableGen initializer
// is a code or string initializer. Returns the empty StringRef otherwise. // is a code or string initializer. Returns the empty StringRef otherwise.
static StringRef getValueAsString(const Init *init) { 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)) if (const auto *str = dyn_cast<StringInit>(init))
return str->getValue().trim(); return str->getValue().trim();
return {}; return {};

View File

@ -38,7 +38,7 @@ std::string Dialect::getCppClassName() const {
static StringRef getAsStringOrEmpty(const llvm::Record &record, static StringRef getAsStringOrEmpty(const llvm::Record &record,
StringRef fieldName) { StringRef fieldName) {
if (auto valueInit = record.getValueInit(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 record.getValueAsString(fieldName);
} }
return ""; return "";

View File

@ -547,12 +547,12 @@ StringRef Operator::getSummary() const {
bool Operator::hasAssemblyFormat() const { bool Operator::hasAssemblyFormat() const {
auto *valueInit = def.getValueInit("assemblyFormat"); auto *valueInit = def.getValueInit("assemblyFormat");
return isa<llvm::CodeInit, llvm::StringInit>(valueInit); return isa<llvm::StringInit>(valueInit);
} }
StringRef Operator::getAssemblyFormat() const { StringRef Operator::getAssemblyFormat() const {
return TypeSwitch<llvm::Init *, StringRef>(def.getValueInit("assemblyFormat")) return TypeSwitch<llvm::Init *, StringRef>(def.getValueInit("assemblyFormat"))
.Case<llvm::StringInit, llvm::CodeInit>( .Case<llvm::StringInit>(
[&](auto *init) { return init->getValue(); }); [&](auto *init) { return init->getValue(); });
} }

View File

@ -55,7 +55,7 @@ bool DagLeaf::isEnumAttrCase() const {
} }
bool DagLeaf::isStringAttr() const { bool DagLeaf::isStringAttr() const {
return isa<llvm::StringInit, llvm::CodeInit>(def); return isa<llvm::StringInit>(def);
} }
Constraint DagLeaf::getAsConstraint() const { Constraint DagLeaf::getAsConstraint() const {

View File

@ -46,7 +46,7 @@ Optional<StringRef> TypeConstraint::getBuilderCall() const {
if (!builderCall || !builderCall->getValue()) if (!builderCall || !builderCall->getValue())
return llvm::None; return llvm::None;
return TypeSwitch<llvm::Init *, Optional<StringRef>>(builderCall->getValue()) return TypeSwitch<llvm::Init *, Optional<StringRef>>(builderCall->getValue())
.Case<llvm::StringInit, llvm::CodeInit>([&](auto *init) { .Case<llvm::StringInit>([&](auto *init) {
StringRef value = init->getValue(); StringRef value = init->getValue();
return value.empty() ? Optional<StringRef>() : value; return value.empty() ? Optional<StringRef>() : value;
}) })

View File

@ -78,10 +78,10 @@ llvm::Optional<StringRef> TypeDef::getMnemonic() const {
return def->getValueAsOptionalString("mnemonic"); return def->getValueAsOptionalString("mnemonic");
} }
llvm::Optional<StringRef> TypeDef::getPrinterCode() const { llvm::Optional<StringRef> TypeDef::getPrinterCode() const {
return def->getValueAsOptionalCode("printer"); return def->getValueAsOptionalString("printer");
} }
llvm::Optional<StringRef> TypeDef::getParserCode() const { llvm::Optional<StringRef> TypeDef::getParserCode() const {
return def->getValueAsOptionalCode("parser"); return def->getValueAsOptionalString("parser");
} }
bool TypeDef::genAccessors() const { bool TypeDef::genAccessors() const {
return def->getValueAsBit("genAccessors"); return def->getValueAsBit("genAccessors");
@ -114,7 +114,7 @@ llvm::Optional<StringRef> TypeParameter::getAllocator() const {
llvm::RecordVal *code = typeParameter->getDef()->getValue("allocator"); llvm::RecordVal *code = typeParameter->getDef()->getValue("allocator");
if (!code) if (!code)
return llvm::Optional<StringRef>(); 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(); return ci->getValue();
if (isa<llvm::UnsetInit>(code->getValue())) if (isa<llvm::UnsetInit>(code->getValue()))
return llvm::Optional<StringRef>(); return llvm::Optional<StringRef>();

View File

@ -137,7 +137,7 @@ static std::string replaceAllSubstrs(std::string str, const std::string &match,
static inline bool hasStringAttribute(const Record &record, static inline bool hasStringAttribute(const Record &record,
StringRef fieldName) { StringRef fieldName) {
auto valueInit = record.getValueInit(fieldName); auto valueInit = record.getValueInit(fieldName);
return isa<CodeInit, StringInit>(valueInit); return isa<StringInit>(valueInit);
} }
static std::string getArgumentName(const Operator &op, int index) { static std::string getArgumentName(const Operator &op, int index) {
@ -1796,15 +1796,15 @@ void OpEmitter::genPrinter() {
return; return;
auto valueInit = def.getValueInit("printer"); auto valueInit = def.getValueInit("printer");
CodeInit *codeInit = dyn_cast<CodeInit>(valueInit); StringInit *stringInit = dyn_cast<StringInit>(valueInit);
if (!codeInit) if (!stringInit)
return; return;
auto *method = auto *method =
opClass.addMethodAndPrune("void", "print", "::mlir::OpAsmPrinter &", "p"); opClass.addMethodAndPrune("void", "print", "::mlir::OpAsmPrinter &", "p");
FmtContext fctx; FmtContext fctx;
fctx.addSubst("cppClass", opClass.getClassName()); 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); method->body() << " " << tgfmt(printer, &fctx);
} }
@ -1816,8 +1816,8 @@ void OpEmitter::genVerifier() {
<< "return ::mlir::failure();\n"; << "return ::mlir::failure();\n";
auto *valueInit = def.getValueInit("verifier"); auto *valueInit = def.getValueInit("verifier");
CodeInit *codeInit = dyn_cast<CodeInit>(valueInit); StringInit *stringInit = dyn_cast<StringInit>(valueInit);
bool hasCustomVerify = codeInit && !codeInit->getValue().empty(); bool hasCustomVerify = stringInit && !stringInit->getValue().empty();
populateSubstitutions(op, "this->getAttr", "this->getODSOperands", populateSubstitutions(op, "this->getAttr", "this->getODSOperands",
"this->getODSResults", verifyCtx); "this->getODSResults", verifyCtx);
@ -1841,7 +1841,7 @@ void OpEmitter::genVerifier() {
if (hasCustomVerify) { if (hasCustomVerify) {
FmtContext fctx; FmtContext fctx;
fctx.addSubst("cppClass", opClass.getClassName()); 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); body << " " << tgfmt(printer, &fctx);
} else { } else {
body << " return ::mlir::success();\n"; body << " return ::mlir::success();\n";