Index: llvm/include/llvm/Remarks/OptRemarkDiagBase.td =================================================================== --- /dev/null +++ llvm/include/llvm/Remarks/OptRemarkDiagBase.td @@ -0,0 +1,38 @@ +//==- OptRemarkDiagBase.td - Opt Remark Diag TableGen base ---*- tablegen -*-=// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the classes which should be used to define new +// optimization remarks using a TableGen based code generator. +// +//===----------------------------------------------------------------------===// + +class OptRemarkGroup { + string Group = group; + int StartID = start; +} + +class OptRemarkKind { + string Kind = kind; +} + +def Kind_General : OptRemarkKind<"General">; +def Kind_Missed : OptRemarkKind<"Missed">; +def Kind_Analysis : OptRemarkKind<"Analysis">; + +class OptRemark { + string RemarkName = Name; + string FormatStr = Format; + string VerboseFormatStr = FormatVerbose; + OptRemarkGroup Group = ?; + OptRemarkKind Kind = Kind_General; +} + +class Kind { OptRemarkKind Kind = kind; } +class Group { OptRemarkGroup Group = group; } \ No newline at end of file Index: llvm/test/TableGen/opt-remark-diag.td =================================================================== --- /dev/null +++ llvm/test/TableGen/opt-remark-diag.td @@ -0,0 +1,56 @@ +// RUN: llvm-tblgen -gen-optremark-diag-kinds -I %p/../../include %s 2>&1 | FileCheck --check-prefix=CHECK-KINDS %s +// RUN: llvm-tblgen -gen-optremark-diag-tbl -I %p/../../include %s 2>&1 | FileCheck --check-prefix=CHECK-TBL %s +// RUN: llvm-tblgen -gen-optremark-diag-enums -I %p/../../include %s 2>&1 | FileCheck --check-prefix=CHECK-ENUMS %s + +// Note: The "CHECK-KINDS" checks depend on the kinds defined in the +// llvm/Remarks/OptRemarkDiagBase.td file. There should not be +// kinds defined outside of that file. +// CHECK-KINDS: enum OptRemarkDiagKinds { +// CHECK-KINDS-NEXT: ORDK_Analysis, +// CHECK-KINDS-NEXT: ORDK_General, +// CHECK-KINDS-NEXT: ORDK_Missed, +// CHECK-KINDS-NEXT: }; + +// CHECK-TBL: OPT_REMARK(remark_example_remark, "RemarkName", "Test1", ORDK_General, "Format string with optional specifier like %{Arg}", "Verbose format string") +// CHECK-TBL: OPT_REMARK(remark_example_remark2, "RemarkName2", "Test1", ORDK_Missed, "Missed format string", "") +// CHECK-TBL: OPT_REMARK(remark_example_remark3, "RemarkName3", "Test1", ORDK_Analysis, "Analysis format string", "") +// CHECK-TBL: OPT_REMARK(remark_example_remark4, "RemarkName4", "Test2", ORDK_Missed, "Format string", "") +// CHECK-TBL: OPT_REMARK(remark_example_remark5, "RemarkName5", "Test1", ORDK_Analysis, "Format string five", "") + +// CHECK-ENUMS: enum OptRemarkDiagGroup_Test1 { +// CHECK-ENUMS: RemarkName = 10000, +// CHECK-ENUMS: RemarkName2, +// CHECK-ENUMS: RemarkName3, +// CHECK-ENUMS: RemarkName5, +// CHECK-ENUMS: }; +// CHECK-ENUMS: enum OptRemarkDiagGroup_Test2 { +// CHECK-ENUMS: RemarkName4 = 11000, +// CHECK-ENUMS: }; + +include "llvm/Remarks/OptRemarkDiagBase.td" + +def Group_Test1 : OptRemarkGroup<"Test1", 10000>; +def Group_Test2 : OptRemarkGroup<"Test2", 11000>; + +let Group = Group_Test1 in { + + def remark_example_remark : OptRemark<"RemarkName", + "Format string with optional specifier like %{Arg}", + "Verbose format string">; + def remark_example_remark2 : OptRemark<"RemarkName2", + "Missed format string">, Kind; + def remark_example_remark3 : OptRemark<"RemarkName3", + "Analysis format string">, Kind; +} + +let Group = Group_Test2, Kind = Kind_Missed in { + + def remark_example_remark4 : OptRemark<"RemarkName4", + "Format string">; +} + +let Kind = Kind_Analysis in { + + def remark_example_remark5 : OptRemark<"RemarkName5", + "Format string five">, Group; +} Index: llvm/utils/TableGen/CMakeLists.txt =================================================================== --- llvm/utils/TableGen/CMakeLists.txt +++ llvm/utils/TableGen/CMakeLists.txt @@ -35,6 +35,7 @@ IntrinsicEmitter.cpp OptEmitter.cpp OptParserEmitter.cpp + OptRemarkDiagEmitter.cpp OptRSTEmitter.cpp PredicateExpander.cpp PseudoLoweringEmitter.cpp Index: llvm/utils/TableGen/OptRemarkDiagEmitter.cpp =================================================================== --- /dev/null +++ llvm/utils/TableGen/OptRemarkDiagEmitter.cpp @@ -0,0 +1,138 @@ +//===- OptRemarkDiagEmitter.cpp - Helper for emitting options. ------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/TableGen/Record.h" + +namespace { + +std::string GetRemarkGroupName(llvm::Record *Remark) { + llvm::Record *Group = Remark->getValueAsDef("Group"); + assert(Group && "OptRemark defined with no group!"); + return Group->getValueAsString("Group").str(); +} + +int64_t GetRemarkGroupStartID(llvm::Record *Remark) { + llvm::Record *Group = Remark->getValueAsDef("Group"); + assert(Group && "OptRemark defined with no group!"); + return Group->getValueAsInt("StartID"); +} + +std::string GetRemarkKindEnum(llvm::Record *Remark) { + llvm::Record *Kind = Remark->getValueAsDef("Kind"); + assert(Kind && "OptRemark defined with no kind!"); + return "ORDK_" + Kind->getValueAsString("Kind").str(); +} + +} // anonymous namespace + +namespace llvm { + +/// EmitOptRemarkDiagKinds - This tablegen backend takes an input .td file +/// describing a set of optimization remarks kinds and emits an enum +/// defining identifiers for each kind: +/// +/// The expected input format is: +/// +/// class OptRemarkKind { +/// string Kind = kind; +/// } +/// +/// def Kind_General : OptRemarkKind<"General">; +/// def Kind_Missed : OptRemarkKind<"Missed">; +/// def Kind_Analysis : OptRemarkKind<"Analysis">; +/// +/// This will be transformed into this format: +/// +/// enum OptRemarkDiagKinds { +/// ORDK_General, +/// ORDK_Missed, +/// ORDK_Analysis, +/// }; + +void EmitOptRemarkDiagKinds(RecordKeeper &Records, raw_ostream &OS) { + std::vector Remarks = + Records.getAllDerivedDefinitions("OptRemarkKind"); + OS << "\nenum OptRemarkDiagKinds {\n"; + for (Record *Remark : Remarks) { + OS << " ORDK_" << Remark->getValueAsString("Kind") << ",\n"; + } + OS << "};\n"; +} + +/// EmitOptRemarkDiagTable - This tablegen backend takes an input .td file +/// describing a list of optimization remarks and emits a series of macros +/// that will be associate an ID with each remark and allow the associated +/// strings to be looked up from the ID. +/// +/// The expected input format for each diagnostic is: +/// +/// def Group_Test : OptRemarkGroup<"Test", 10000>; +/// +/// let Group = Group_Test in { +/// def remark_example_remark : OptRemark<"RemarkName", +/// "Format string with optional specifier like %0" +/// "Verbose format string">[, Kind]]; +/// } +/// +/// This will be transformed into this format: +/// +/// OPT_REMARK(remark_example_remark, +/// "RemarkName", "Test", ORDK_[General|Missed|Analysis], +/// "Format string with optional specifier like %{Arg}", +/// "Verbose format string") + +void EmitOptRemarkDiagTable(RecordKeeper &Records, raw_ostream &OS) { + std::vector Remarks = Records.getAllDerivedDefinitions("OptRemark"); + for (Record *Remark : Remarks) { + OS << "OPT_REMARK(" << Remark->getName() << ", " + << "\"" << Remark->getValueAsString("RemarkName") << "\", " + << "\"" << GetRemarkGroupName(Remark) << "\", " + << GetRemarkKindEnum(Remark) << ", " + << "\"" << Remark->getValueAsString("FormatStr") << "\", " + << "\"" << Remark->getValueAsString("VerboseFormatStr") << "\")\n"; + } +} + +/// EmitOptRemarkDiagEnums - This tablegen backend takes an input .td file +/// describing a list of optimization remarks and emits a group enums for +/// the remarks. It is assumed that a 'diag' namespace wrapper will be +/// generated around this enum elsewhere. +/// +/// The expected input format is the same as for EmitOptRemarkDiagTable. +/// This will be transformed into this format: +/// +/// enum OptRemarkDiagGroup_Test { +/// remark_example_remark = 10000, +/// }; + +void EmitOptRemarkDiagEnums(RecordKeeper &Records, raw_ostream &OS) { + StringMap> GroupMap; + std::vector Remarks = Records.getAllDerivedDefinitions("OptRemark"); + for (Record *Remark : Remarks) + GroupMap[GetRemarkGroupName(Remark)].push_back(Remark); + for (auto &Group : GroupMap) { + auto &Remarks = Group.second; + bool First = true; + assert(Remarks.size() > 0 && "Empty remark group found!"); + OS << "\nenum OptRemarkDiagGroup_" << Group.first() << " {\n"; + for (auto *Remark : Remarks) { + OS << " " << Remark->getValueAsString("RemarkName"); + if (First) { + First = false; + int64_t Start = GetRemarkGroupStartID(Remark); + OS << " = " << Start; + } + OS << ",\n"; + } + OS << "};\n\n"; + } +} + +} // namespace llvm Index: llvm/utils/TableGen/TableGen.cpp =================================================================== --- llvm/utils/TableGen/TableGen.cpp +++ llvm/utils/TableGen/TableGen.cpp @@ -54,6 +54,9 @@ GenRegisterBank, GenExegesis, GenAutomata, + GenOptRemarkDiagKinds, + GenOptRemarkDiagEnums, + GenOptRemarkDiagTable, }; namespace llvm { @@ -122,7 +125,13 @@ "Generate registers bank descriptions"), clEnumValN(GenExegesis, "gen-exegesis", "Generate llvm-exegesis tables"), - clEnumValN(GenAutomata, "gen-automata", "Generate generic automata"))); + clEnumValN(GenAutomata, "gen-automata", "Generate generic automata"), + clEnumValN(GenOptRemarkDiagKinds, "gen-optremark-diag-kinds", + "Generate optimization remark diagnostics kinds"), + clEnumValN(GenOptRemarkDiagEnums, "gen-optremark-diag-enums", + "Generate optimization remark diagnostics enums"), + clEnumValN(GenOptRemarkDiagTable, "gen-optremark-diag-tbl", + "Generate optimization remark diagnostics table"))); cl::OptionCategory PrintEnumsCat("Options for -print-enums"); cl::opt Class("class", cl::desc("Print Enum list for this class"), @@ -247,6 +256,15 @@ case GenAutomata: EmitAutomata(Records, OS); break; + case GenOptRemarkDiagKinds: + EmitOptRemarkDiagKinds(Records, OS); + break; + case GenOptRemarkDiagEnums: + EmitOptRemarkDiagEnums(Records, OS); + break; + case GenOptRemarkDiagTable: + EmitOptRemarkDiagTable(Records, OS); + break; } return false; Index: llvm/utils/TableGen/TableGenBackends.h =================================================================== --- llvm/utils/TableGen/TableGenBackends.h +++ llvm/utils/TableGen/TableGenBackends.h @@ -90,6 +90,9 @@ void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS); void EmitExegesis(RecordKeeper &RK, raw_ostream &OS); void EmitAutomata(RecordKeeper &RK, raw_ostream &OS); +void EmitOptRemarkDiagKinds(RecordKeeper &Records, raw_ostream &OS); +void EmitOptRemarkDiagEnums(RecordKeeper &Records, raw_ostream &OS); +void EmitOptRemarkDiagTable(RecordKeeper &Records, raw_ostream &OS); } // End llvm namespace