//===- MatchTable.h -------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // /// \file /// This file contains the generic emitter for the GlobalISel Match Table /// system. This file only contains the code used to emit the table itself. /// //===----------------------------------------------------------------------===// #ifndef LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_MATCHTABLE_MATCHTABLE_H #define LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_MATCHTABLE_MATCHTABLE_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" #include namespace llvm { class raw_ostream; class Record; namespace gi { class Matcher; class MatchTable; void emitEncodingMacrosDef(raw_ostream &OS); void emitEncodingMacrosUndef(raw_ostream &OS); std::string getNameForFeatureBitset(ArrayRef FeatureBitset, int HwModeIdx); /// A record to be stored in a MatchTable. /// /// This class represents any and all output that may be required to emit the /// MatchTable. Instances are most often configured to represent an opcode or /// value that will be emitted to the table with some formatting but it can also /// represent commas, comments, and other formatting instructions. struct MatchTableRecord { enum RecordFlagsBits { MTRF_None = 0x0, /// Causes EmitStr to be formatted as comment when emitted. MTRF_Comment = 0x1, /// Causes the record value to be followed by a comma when emitted. MTRF_CommaFollows = 0x2, /// Causes the record value to be followed by a line break when emitted. MTRF_LineBreakFollows = 0x4, /// Indicates that the record defines a label and causes an additional /// comment to be emitted containing the index of the label. MTRF_Label = 0x8, /// Causes the record to be emitted as the index of the label specified by /// LabelID along with a comment indicating where that label is. MTRF_JumpTarget = 0x10, /// Causes the formatter to add a level of indentation before emitting the /// record. MTRF_Indent = 0x20, /// Causes the formatter to remove a level of indentation after emitting the /// record. MTRF_Outdent = 0x40, /// Causes the formatter to not use encoding macros to emit this multi-byte /// value. MTRF_PreEncoded = 0x80, }; /// When MTRF_Label or MTRF_JumpTarget is used, indicates a label id to /// reference or define. unsigned LabelID; /// The string to emit. Depending on the MTRF_* flags it may be a comment, a /// value, a label name. std::string EmitStr; private: /// The number of MatchTable elements described by this record. Comments are 0 /// while values are typically 1. Values >1 may occur when we need to emit /// values that exceed the size of a MatchTable element. unsigned NumElements; public: /// A bitfield of RecordFlagsBits flags. unsigned Flags; MatchTableRecord(std::optional LabelID_, StringRef EmitStr, unsigned NumElements, unsigned Flags) : LabelID(LabelID_.value_or(~0u)), EmitStr(EmitStr), NumElements(NumElements), Flags(Flags) { assert((!LabelID_ || LabelID != ~0u) && "This value is reserved for non-labels"); } MatchTableRecord(const MatchTableRecord &Other) = default; MatchTableRecord(MatchTableRecord &&Other) = default; /// Useful if a Match Table Record gets optimized out void turnIntoComment() { Flags |= MTRF_Comment; Flags &= ~MTRF_CommaFollows; NumElements = 0; } void emit(raw_ostream &OS, bool LineBreakNextAfterThis, const MatchTable &Table) const; unsigned size() const { return NumElements; } }; /// Holds the contents of a generated MatchTable to enable formatting and the /// necessary index tracking needed to support GIM_Try. class MatchTable { /// An unique identifier for the table. The generated table will be named /// MatchTable${ID}. unsigned ID; /// The records that make up the table. Also includes comments describing the /// values being emitted and line breaks to format it. std::vector Contents; /// The currently defined labels. DenseMap LabelMap; /// Tracks the sum of MatchTableRecord::NumElements as the table is built. unsigned CurrentSize = 0; /// A unique identifier for a MatchTable label. unsigned CurrentLabelID = 0; /// Determines if the table should be instrumented for rule coverage tracking. bool IsWithCoverage; /// Whether this table is for the GISel combiner. bool IsCombinerTable; public: static MatchTableRecord LineBreak; static MatchTableRecord Comment(StringRef Comment); static MatchTableRecord Opcode(StringRef Opcode, int IndentAdjust = 0); static MatchTableRecord NamedValue(unsigned NumBytes, StringRef NamedValue); static MatchTableRecord NamedValue(unsigned NumBytes, StringRef Namespace, StringRef NamedValue); static MatchTableRecord IntValue(unsigned NumBytes, int64_t IntValue); static MatchTableRecord ULEB128Value(uint64_t IntValue); static MatchTableRecord Label(unsigned LabelID); static MatchTableRecord JumpTarget(unsigned LabelID); MatchTable(bool WithCoverage, bool IsCombinerTable, unsigned ID = 0) : ID(ID), IsWithCoverage(WithCoverage), IsCombinerTable(IsCombinerTable) { } bool isWithCoverage() const { return IsWithCoverage; } bool isCombiner() const { return IsCombinerTable; } void push_back(const MatchTableRecord &Value) { if (Value.Flags & MatchTableRecord::MTRF_Label) defineLabel(Value.LabelID); Contents.push_back(Value); CurrentSize += Value.size(); } unsigned allocateLabelID() { return CurrentLabelID++; } void defineLabel(unsigned LabelID) { LabelMap.try_emplace(LabelID, CurrentSize); } unsigned getLabelIndex(unsigned LabelID) const { const auto I = LabelMap.find(LabelID); assert(I != LabelMap.end() && "Use of undeclared label"); return I->second; } void emitUse(raw_ostream &OS) const; void emitDeclaration(raw_ostream &OS) const; }; inline MatchTable &operator<<(MatchTable &Table, const MatchTableRecord &Value) { Table.push_back(Value); return Table; } } // namespace gi } // namespace llvm #endif