mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-02 02:38:04 +00:00
[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:
parent
1365718778
commit
415fab6f67
@ -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);
|
||||
}
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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``
|
||||
~~~~~~~~~~~
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -58,7 +58,6 @@ public:
|
||||
enum RecTyKind {
|
||||
BitRecTyKind,
|
||||
BitsRecTyKind,
|
||||
CodeRecTyKind,
|
||||
IntRecTyKind,
|
||||
StringRecTyKind,
|
||||
ListRecTyKind,
|
||||
@ -138,24 +137,6 @@ public:
|
||||
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 @@ protected:
|
||||
IK_FirstTypedInit,
|
||||
IK_BitInit,
|
||||
IK_BitsInit,
|
||||
IK_CodeInit,
|
||||
IK_DagInit,
|
||||
IK_DefInit,
|
||||
IK_FieldInit,
|
||||
@ -597,16 +577,18 @@ public:
|
||||
|
||||
/// "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 @@ public:
|
||||
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; }
|
||||
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() + "\""; }
|
||||
|
||||
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 {
|
||||
return "[{" + Value.str() + "}]";
|
||||
if (Format == SF_String)
|
||||
return "\"" + Value.str() + "\"";
|
||||
else
|
||||
return "[{" + Value.str() + "}]";
|
||||
}
|
||||
|
||||
std::string getAsUnquotedString() const override {
|
||||
@ -1438,6 +1397,9 @@ public:
|
||||
/// 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 @@ public:
|
||||
/// 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.
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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 +
|
||||
|
@ -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]+'.
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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";
|
||||
|
@ -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 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
|
||||
|
@ -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";
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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" }]>;
|
||||
|
@ -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";
|
||||
|
@ -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 {
|
||||
|
@ -150,7 +150,7 @@ protected:
|
||||
|
||||
/// 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 @@ public:
|
||||
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"
|
||||
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 @@ private:
|
||||
|
||||
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 @@ private:
|
||||
|
||||
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\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "llvm/Support/SMLoc.h"
|
||||
|
||||
namespace llvm {
|
||||
class CodeInit;
|
||||
class DefInit;
|
||||
class Record;
|
||||
class StringInit;
|
||||
|
@ -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 {};
|
||||
|
@ -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 "";
|
||||
|
@ -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(); });
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
})
|
||||
|
@ -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>();
|
||||
|
@ -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";
|
||||
|
Loading…
Reference in New Issue
Block a user