diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -1764,6 +1764,73 @@ list > ValueCols = []; } +//===----------------------------------------------------------------------===// +// EnumMember - Used in conjunction with an Enum to specify members of an +// enumeration. Can optionally have a specific integer value. +// +class EnumMember { + // If set, this is the explicit value given to the enumeration member. If + // unset, the value is implied by the member's order in the Enum. + field int Value = ?; + + // If given, this is the name given to the enumeration member. If unset, + // the name of the Record definition is used. + field string Name = name; + + // The field used by the enumeration 'Print' and 'Match' methods when + // printing or matching enumeration members. See below. + field string String = NAME; +} + +//===----------------------------------------------------------------------===// +// EnumMemberVal - Convenience class that can be used in the common case that +// an enum member has a specific value. +// +class EnumMemberVal : EnumMember { + let Value = v; + let Name = name; +} + +//===----------------------------------------------------------------------===// +// Enum - This class is used to automatically defined and link enumerations +// between TableGen and C++. An enum is generated for each def of Enum with a +// non-empty list of EnumMember instances: +// def A : EnumMember; +// def B : EnumMember; +// def C : EnumMemberVal<3, "third">; +// def MyEnum : Enum<[A, B, C]>; +// Generates: +// enum MyEnum { +// A, +// B, +// third = 3, +// }; +// +class Enum members> { + // If set, the name of the enum. If unset, the name of the class is used. + field string Name = NAME; + + // If set, the underlying type of the enumeration. + field string UnderlyingTy = ?; + + // When this bit is set, the enum will be emitted as a C++ enum class. + field bit IsClass = false; + + // The (ordered) list of enumeration members. + field list Members = members; + + // The name of the method used to get the String value of enumeration + // values. The generated method returns StringRef, and switches over all + // enum members with an llvm_unreachable on the default case. + field string ToStringMethod = ?; + + // The name of the method used to match from the String value back to the + // enum value. If set, the String field of each enum member must be unique. + // The method returns an Optional<>, where None is returned if there is no + // match. + field string FromStringMethod = ?; +} + //===----------------------------------------------------------------------===// // Pull in the common support for calling conventions. // diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt --- a/llvm/lib/Target/RISCV/CMakeLists.txt +++ b/llvm/lib/Target/RISCV/CMakeLists.txt @@ -15,6 +15,7 @@ tablegen(LLVM RISCVGenRegisterInfo.inc -gen-register-info) tablegen(LLVM RISCVGenSearchableTables.inc -gen-searchable-tables) tablegen(LLVM RISCVGenSubtargetInfo.inc -gen-subtarget) +tablegen(LLVM RISCVGenEnums.inc -gen-enums) add_public_tablegen_target(RISCVCommonTableGen) diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -97,29 +97,11 @@ UsesMaskPolicyMask = 1 << UsesMaskPolicyShift, }; -// Match with the definitions in RISCVInstrFormats.td -enum VConstraintType { - NoConstraint = 0, - VS2Constraint = 0b001, - VS1Constraint = 0b010, - VMConstraint = 0b100, -}; - -enum VLMUL : uint8_t { - LMUL_1 = 0, - LMUL_2, - LMUL_4, - LMUL_8, - LMUL_RESERVED, - LMUL_F8, - LMUL_F4, - LMUL_F2 -}; - -enum { - TAIL_AGNOSTIC = 1, - MASK_AGNOSTIC = 2, -}; +// Include enumerations from TableGen +#define GET_VConstraintType_ENUM +#define GET_VLMUL_ENUM +#define GET_RVVPolicy_ENUM +#include "RISCVGenEnums.inc" // Helper functions to read TSFlags. /// \returns the format of the instruction. diff --git a/llvm/lib/Target/RISCV/RISCVInstrFormats.td b/llvm/lib/Target/RISCV/RISCVInstrFormats.td --- a/llvm/lib/Target/RISCV/RISCVInstrFormats.td +++ b/llvm/lib/Target/RISCV/RISCVInstrFormats.td @@ -49,14 +49,16 @@ def InstFormatCJ : InstFormat<16>; def InstFormatOther : InstFormat<17>; -class RISCVVConstraint val> { - bits<3> Value = val; -} +class RISCVVConstraint val> : EnumMemberVal; + def NoConstraint : RISCVVConstraint<0b000>; def VS2Constraint : RISCVVConstraint<0b001>; def VS1Constraint : RISCVVConstraint<0b010>; def VMConstraint : RISCVVConstraint<0b100>; +def VConstraintType : Enum<[NoConstraint, VS2Constraint, + VS1Constraint, VMConstraint]>; + // Illegal instructions: // // * The destination vector register group for a masked vector instruction diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td b/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td @@ -41,15 +41,38 @@ defvar TAIL_UNDISTURBED = 0; defvar TAIL_AGNOSTIC = 1; +defvar MASK_AGNOSTIC = 2; + +def RVVPolicy : Enum<[ + EnumMemberVal, + EnumMemberVal, + EnumMemberVal]>; //===----------------------------------------------------------------------===// // Utilities. //===----------------------------------------------------------------------===// +class LMUL v> : EnumMemberVal; + +def LMUL_1 : LMUL<0b000>; +def LMUL_2 : LMUL<0b001>; +def LMUL_4 : LMUL<0b010>; +def LMUL_8 : LMUL<0b011>; +def LMUL_RESERVED : LMUL<0b100>; +def LMUL_F8 : LMUL<0b101>; +def LMUL_F4 : LMUL<0b110>; +def LMUL_F2 : LMUL<0b111>; + +def VLMULNum : Enum<[LMUL_1, LMUL_2, LMUL_4, LMUL_8, + LMUL_RESERVED, LMUL_F8, LMUL_F4, LMUL_F2]> { + let Name = "VLMUL"; + let UnderlyingTy = "uint8_t"; +} + // This class describes information associated to the LMUL. -class LMULInfo { - bits<3> value = lmul; // This is encoded as the vlmul field of vtype. + bits<3> value = lmul.Value; // This is encoded as the vlmul field of vtype. VReg vrclass = regclass; VReg wvrclass = wregclass; VReg f8vrclass = f8regclass; @@ -60,14 +83,14 @@ } // Associate LMUL with tablegen records of register classes. -def V_M1 : LMULInfo<0b000, 8, VR, VRM2, VR, VR, VR, "M1">; -def V_M2 : LMULInfo<0b001, 16, VRM2, VRM4, VR, VR, VR, "M2">; -def V_M4 : LMULInfo<0b010, 32, VRM4, VRM8, VRM2, VR, VR, "M4">; -def V_M8 : LMULInfo<0b011, 64, VRM8,/*NoVReg*/VR, VRM4, VRM2, VR, "M8">; - -def V_MF8 : LMULInfo<0b101, 1, VR, VR,/*NoVReg*/VR,/*NoVReg*/VR,/*NoVReg*/VR, "MF8">; -def V_MF4 : LMULInfo<0b110, 2, VR, VR, VR,/*NoVReg*/VR,/*NoVReg*/VR, "MF4">; -def V_MF2 : LMULInfo<0b111, 4, VR, VR, VR, VR,/*NoVReg*/VR, "MF2">; +def V_M1 : LMULInfo; +def V_M2 : LMULInfo; +def V_M4 : LMULInfo; +def V_M8 : LMULInfo; + +def V_MF8 : LMULInfo; +def V_MF4 : LMULInfo; +def V_MF2 : LMULInfo; // Used to iterate over all possible LMULs. defvar MxList = [V_MF8, V_MF4, V_MF2, V_M1, V_M2, V_M4, V_M8]; diff --git a/llvm/test/TableGen/EnumEmitter.td b/llvm/test/TableGen/EnumEmitter.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/EnumEmitter.td @@ -0,0 +1,129 @@ +// RUN: llvm-tblgen -gen-enums -I %p/../../include %s 2>&1 | FileCheck %s + +include "llvm/Target/Target.td" + +def One : EnumMember; +def Two : EnumMember; + +def MyEnum : Enum<[One, Two]>; + +// CHECK-LABEL: #ifdef GET_MyEnum_ENUM +// CHECK-LABEL: enum MyEnum { +// CHECK-NEXT: One, +// CHECK-NEXT: Two, +// CHECK-NEXT: }; +// CHECK-LABEL: #endif // GET_MyEnum_ENUM + +def MyEnumEnumName : Enum<[One, Two]> { + let Name = "SomethingElse"; +} + +// CHECK-LABEL: #ifdef GET_SomethingElse_ENUM +// CHECK-LABEL: enum SomethingElse { +// CHECK-NEXT: One, +// CHECK-NEXT: Two, +// CHECK-NEXT: }; +// CHECK-LABEL: #endif // GET_SomethingElse_ENUM + +def MyEnumMemberName : Enum<[EnumMember<"one">, EnumMember<"two">]>; + +// CHECK-LABEL: #ifdef GET_MyEnumMemberName_ENUM +// CHECK-LABEL: enum MyEnumMemberName { +// CHECK-NEXT: one, +// CHECK-NEXT: two, +// CHECK-NEXT: }; +// CHECK-LABEL: #endif // GET_MyEnumMemberName_ENUM + +def OneV : EnumMemberVal<1>; +def TwoV : EnumMemberVal<2>; + +def MyEnumV : Enum<[OneV, TwoV]>; + +// CHECK-LABEL: #ifdef GET_MyEnumV_ENUM +// CHECK-LABEL: enum MyEnumV { +// CHECK-NEXT: OneV = 1, +// CHECK-NEXT: TwoV = 2, +// CHECK-NEXT: }; +// CHECK-LABEL: #endif // GET_MyEnumV_ENUM + +def MyEnumVClass : Enum<[OneV, TwoV]> { + let IsClass = true; +} + +// CHECK-LABEL: #ifdef GET_MyEnumVClass_ENUM +// CHECK-LABEL: enum class MyEnumVClass { +// CHECK-NEXT: OneV = 1, +// CHECK-NEXT: TwoV = 2, +// CHECK-NEXT: }; +// CHECK-LABEL: #endif // GET_MyEnumVClass_ENUM + +def MyEnumVClassUnsignedShort : Enum<[OneV, TwoV]> { + let IsClass = true; + let UnderlyingTy = "unsigned short"; +} + +// CHECK-LABEL: #ifdef GET_MyEnumVClassUnsignedShort_ENUM +// CHECK-LABEL: enum class MyEnumVClassUnsignedShort : unsigned short { +// CHECK-NEXT: OneV = 1, +// CHECK-NEXT: TwoV = 2, +// CHECK-NEXT: }; +// CHECK-LABEL: #endif // GET_MyEnumVClassUnsignedShort_ENUM + +def MyEnumVMixed : Enum<[One, TwoV]>; + +// CHECK-LABEL: #ifdef GET_MyEnumVMixed_ENUM +// CHECK-LABEL: enum MyEnumVMixed { +// CHECK-NEXT: One, +// CHECK-NEXT: TwoV = 2, +// CHECK-NEXT: }; +// CHECK-LABEL: #endif // GET_MyEnumVMixed_ENUM + +def THREE : EnumMember { + let String = "three"; +} +def FOUR : EnumMember { + let Name = "Four"; + let String = "four"; +} + +def PrintEnum : Enum<[One, Two, THREE, FOUR]> { + let ToStringMethod = "getPrintEnumAsStr"; + let FromStringMethod = "getPrintEnumFromStr"; +} + +// CHECK-LABEL: #ifdef GET_PrintEnum_ENUM +// CHECK-LABEL: enum PrintEnum { +// CHECK-NEXT: One, +// CHECK-NEXT: Two, +// CHECK-NEXT: THREE, +// CHECK-NEXT: Four, +// CHECK-NEXT: }; +// CHECK-LABEL: #endif // GET_PrintEnum_ENUM + +// CHECK-LABEL: #ifdef GET_PrintEnum_TOSTRING_IMPL +// CHECK-LABEL: static inline StringRef getPrintEnumAsStr(const PrintEnum E) { +// CHECK-NEXT: switch (E) { +// CHECK-NEXT: default: +// CHECK-NEXT: llvm_unreachable("Invalid PrintEnum"); +// CHECK-NEXT: case PrintEnum::One: +// CHECK-NEXT: return "One"; +// CHECK-NEXT: case PrintEnum::Two: +// CHECK-NEXT: return "Two"; +// CHECK-NEXT: case PrintEnum::THREE: +// CHECK-NEXT: return "three"; +// CHECK-NEXT: case PrintEnum::Four: +// CHECK-NEXT: return "four"; +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-LABEL: #endif // GET_PrintEnum_TOSTRING_IMPL + +// CHECK-LABEL: #ifdef GET_PrintEnum_FROMSTRING_IMPL +// CHECK-LABEL: static inline Optional getPrintEnumFromStr(StringRef Str) { +// CHECK-NEXT: return StringSwitch>(Str) +// CHECK-NEXT: .Case("One", PrintEnum::One) +// CHECK-NEXT: .Case("Two", PrintEnum::Two) +// CHECK-NEXT: .Case("three", PrintEnum::THREE) +// CHECK-NEXT: .Case("four", PrintEnum::Four) +// CHECK-NEXT: .Default(None); +// CHECK-NEXT: } +// CHECK-LABEL: #endif // GET_PrintEnum_FROMSTRING_IMPL diff --git a/llvm/test/TableGen/EnumEmitterInvalid.td b/llvm/test/TableGen/EnumEmitterInvalid.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/EnumEmitterInvalid.td @@ -0,0 +1,49 @@ +// RUN: not llvm-tblgen -gen-enums -DERROR1 -I %p/../../include %s 2>&1 | FileCheck %s --check-prefix ERROR1 +// RUN: not llvm-tblgen -gen-enums -DERROR2 -I %p/../../include %s 2>&1 | FileCheck %s --check-prefix ERROR2 +// RUN: not llvm-tblgen -gen-enums -DERROR3 -I %p/../../include %s 2>&1 | FileCheck %s --check-prefix ERROR3 + +include "llvm/Target/Target.td" + +#ifdef ERROR1 + +def Zero : EnumMember; +def One : EnumMember; +def Null : EnumMemberVal<0>; + +def MyEnum : Enum<[Zero, One, Null]> { + let ToStringMethod = "AsStr1"; +} + +#endif // ERROR1 + +// ERROR1: Enum has duplicate values so no ToStringMethod is possible! + +#ifdef ERROR2 + +def Zero : EnumMember; +def One : EnumMember; +def Null : EnumMember<"Zero">; + +def MyEnum : Enum<[Zero, One, Null]> { + let FromStringMethod = "AsStr1"; +} + +// ERROR2: Enum has duplicate enumerator named 'Zero'! + +#endif // ERROR2 + +#ifdef ERROR3 + +def Zero : EnumMember; +def One : EnumMember; +def Null : EnumMember { + let String = "Zero"; +} + +def MyEnum : Enum<[Zero, One, Null]> { + let FromStringMethod = "AsStr1"; +} + +// ERROR3: Enum has duplicate enumerator string 'Zero'! + +#endif // ERROR3 diff --git a/llvm/utils/TableGen/CMakeLists.txt b/llvm/utils/TableGen/CMakeLists.txt --- a/llvm/utils/TableGen/CMakeLists.txt +++ b/llvm/utils/TableGen/CMakeLists.txt @@ -26,6 +26,7 @@ DFAPacketizerEmitter.cpp DirectiveEmitter.cpp DisassemblerEmitter.cpp + EnumEmitter.cpp ExegesisEmitter.cpp FastISelEmitter.cpp FixedLenDecoderEmitter.cpp diff --git a/llvm/utils/TableGen/EnumEmitter.cpp b/llvm/utils/TableGen/EnumEmitter.cpp new file mode 100644 --- /dev/null +++ b/llvm/utils/TableGen/EnumEmitter.cpp @@ -0,0 +1,189 @@ +//===- EnumEmitter.cpp - Generate enums -----------------------------------===// +// +// 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 tablegen backend emits enum definitions which can be used across +/// tablegen and C++. See include/llvm/Target/Target.td for the Enum and +/// EnumMember classes. +/// +/// An enum is created for each definition that derives from the Enum class. +/// At a minimum, the Enum class is given a non-empty list of EnumMember +/// definitions serving as its constituent members/enumerators. It can +/// additionally be given optional underlying types, be defined as a C++ enum +/// class, and have auto-generated to-string and from-string methods: +/// +/// def A : EnumMember; +/// def B : EnumMember; +/// def C : EnumMemberVal<3>; +/// def MyEnum : Enum<[A, B, C]>; +/// +/// Generates: +/// enum MyEnum { +/// A, +/// B, +/// C = 3, +/// }; +/// +/// To- and from-string methods are generated by defining ToStringMethod and +/// FromStringMethod string variables which generate the following methods: +/// static inline StringRef ToStringMethod(const Enum); +/// static inline Optional FromStringMethod(StringRef Str); +/// The ToStringMethod is implemented as a switch over all enumerators +/// returning the enumerator as a StringRef, hitting llvm_unreachable if not +/// found. +/// The FromStringMethod is implemented as a StringSwitch over all enumerators, +/// returning None if not found. +//===----------------------------------------------------------------------===// + +#include "TableGenBackends.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/Support/Debug.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" + +using namespace llvm; + +namespace { +class EnumEmitter { + RecordKeeper &Records; + +public: + EnumEmitter(RecordKeeper &R) : Records(R) {} + + void run(raw_ostream &OS) const; + void emitEnum(const Record *Enum, raw_ostream &OS) const; +}; +} // End anonymous namespace + +void EnumEmitter::run(raw_ostream &OS) const { + auto Enums = Records.getAllDerivedDefinitions("Enum"); + + llvm::sort(Enums, LessRecord()); + + for (const auto *R : Enums) + emitEnum(R, OS); +} + +static StringRef getEnumMemberName(const Record *EM) { + auto Name = EM->getValueAsString("Name"); + if (Name.empty()) + PrintFatalError(EM->getLoc(), "EnumMember has empty Name!"); + return Name; +} + +static StringRef getEnumMemberStr(const Record *EM) { + auto Str = EM->getValueAsString("String"); + if (Str.empty()) + PrintFatalError(EM->getLoc(), "EnumMember has empty String!"); + return Str; +} + +static Optional getEnumMemberVal(const Record *EM) { + if (EM->isValueUnset("Value")) + return None; + return EM->getValueAsInt("Value"); +} + +void EnumEmitter::emitEnum(const Record *Enum, raw_ostream &OS) const { + auto EnumName = Enum->getValueAsString("Name"); + if (EnumName.empty()) + PrintFatalError(Enum->getLoc(), "Enum has empty Name!"); + + const auto &Members = Enum->getValueAsListOfDefs("Members"); + + if (Members.empty()) + return; + + Optional UnderlyingTy = + Enum->getValueAsOptionalString("UnderlyingTy"); + + bool HasDuplicateVals = false; + // Keep track of enumerator values and names, as duplicates would cause C++ + // miscompilations. These would be caught later by the C++ compiler, but it's + // better to flag this as early as possible. + SmallSet EnumValues; + SmallSet EnumMemberNames; + + bool IsClass = Enum->getValueAsBit("IsClass"); + + // Emit the enum definition itself + std::string EnumGuard = ("GET_" + Twine(EnumName) + "_ENUM").str(); + OS << "#ifdef " << EnumGuard << "\n"; + OS << "enum " << (IsClass ? "class " : "") << EnumName; + if (UnderlyingTy) + OS << " : " + *UnderlyingTy; + OS << " {\n"; + for (const auto &P : enumerate(Members)) { + auto EnumMemberName = getEnumMemberName(P.value()); + if (!EnumMemberNames.insert(EnumMemberName).second) + PrintFatalError(Enum->getLoc(), "Enum has duplicate enumerator named '" + + EnumMemberName + "'!"); + OS << " " << EnumMemberName; + if (auto Val = getEnumMemberVal(P.value())) { + OS << " = " << *Val; + HasDuplicateVals |= !EnumValues.insert(*Val).second; + } else { + // Else the value is implied by its ordering. + HasDuplicateVals |= !EnumValues.insert(P.index()).second; + } + OS << ",\n"; + } + + OS << "};\n"; + OS << "#endif // " << EnumGuard << "\n\n"; + + if (auto ToStringMethod = Enum->getValueAsOptionalString("ToStringMethod")) { + if (HasDuplicateVals) + PrintFatalError( + Enum->getLoc(), + "Enum has duplicate values so no ToStringMethod is possible!"); + const char *Param = "E"; + std::string ToStringGuard = ("GET_" + EnumName + "_TOSTRING_IMPL").str(); + // ToString method definition + OS << "#ifdef " << ToStringGuard << "\n"; + OS << "static inline StringRef " << *ToStringMethod << "(const " << EnumName + << " " << Param << ") {\n"; + OS << " switch (" << Param << ") {\n"; + OS << " default:\n"; + OS << " llvm_unreachable(\"Invalid " << EnumName << "\");\n"; + for (const auto *M : Members) { + OS << " case " << EnumName + "::" + getEnumMemberName(M) << ":\n"; + OS << " return \"" << getEnumMemberStr(M) << "\";\n"; + } + OS << " }\n"; + OS << "}\n"; + OS << "#endif // " << ToStringGuard << "\n\n"; + } + + if (auto FromStringMethod = + Enum->getValueAsOptionalString("FromStringMethod")) { + SmallSet SeenStrings; + std::string RetTy = ("Optional<" + EnumName + ">").str(); + std::string FromStringGuard = + ("GET_" + EnumName + "_FROMSTRING_IMPL").str(); + // FromString method definition + OS << "#ifdef " << FromStringGuard << "\n"; + OS << "static inline " << RetTy << " " << *FromStringMethod + << "(StringRef Str) {\n"; + OS << " return StringSwitch<" << RetTy << ">(Str)\n"; + for (const auto *M : Members) { + if (!SeenStrings.insert(getEnumMemberStr(M)).second) + PrintFatalError(M->getLoc(), "Enum has duplicate enumerator string '" + + getEnumMemberStr(M) + "'!"); + OS << " .Case(\"" << getEnumMemberStr(M) << "\", " + << EnumName + "::" + getEnumMemberName(M) << ")\n"; + } + OS << " .Default(None);\n"; + OS << "}\n"; + OS << "#endif // " << FromStringGuard << "\n\n"; + } +} + +void llvm::EmitEnums(RecordKeeper &RK, raw_ostream &OS) { + EnumEmitter(RK).run(OS); +} diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp --- a/llvm/utils/TableGen/TableGen.cpp +++ b/llvm/utils/TableGen/TableGen.cpp @@ -58,6 +58,7 @@ GenAutomata, GenDirectivesEnumDecl, GenDirectivesEnumImpl, + GenEnums, }; namespace llvm { @@ -141,7 +142,8 @@ clEnumValN(GenDirectivesEnumDecl, "gen-directive-decl", "Generate directive related declaration code (header file)"), clEnumValN(GenDirectivesEnumImpl, "gen-directive-impl", - "Generate directive related implementation code"))); + "Generate directive related implementation code"), + clEnumValN(GenEnums, "gen-enums", "Generate enumerations"))); cl::OptionCategory PrintEnumsCat("Options for -print-enums"); cl::opt Class("class", cl::desc("Print Enum list for this class"), @@ -278,6 +280,9 @@ case GenDirectivesEnumImpl: EmitDirectivesImpl(Records, OS); break; + case GenEnums: + EmitEnums(Records, OS); + break; } return false; diff --git a/llvm/utils/TableGen/TableGenBackends.h b/llvm/utils/TableGen/TableGenBackends.h --- a/llvm/utils/TableGen/TableGenBackends.h +++ b/llvm/utils/TableGen/TableGenBackends.h @@ -94,6 +94,7 @@ void EmitAutomata(RecordKeeper &RK, raw_ostream &OS); void EmitDirectivesDecl(RecordKeeper &RK, raw_ostream &OS); void EmitDirectivesImpl(RecordKeeper &RK, raw_ostream &OS); +void EmitEnums(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace