summaryrefslogtreecommitdiffstats
path: root/lldb/utils
diff options
context:
space:
mode:
authorJonas Devlieghere <jonas@devlieghere.com>2019-07-25 21:36:37 +0000
committerJonas Devlieghere <jonas@devlieghere.com>2019-07-25 21:36:37 +0000
commit971f9ca612f22d251631f6b7dcc5efd8324bc0f2 (patch)
tree282cdef9ce40fa67215fe675dc77e76b234f467c /lldb/utils
parentd16a034c7cd33208a86301f05eb4c1a358914475 (diff)
downloadbcm5719-llvm-971f9ca612f22d251631f6b7dcc5efd8324bc0f2.tar.gz
bcm5719-llvm-971f9ca612f22d251631f6b7dcc5efd8324bc0f2.zip
Let tablegen generate property definitions
Property definitions are currently defined in a PropertyDefinition array and have a corresponding enum to index in this array. Unfortunately this is quite error prone. Indeed, just today we found an incorrect merge where a discrepancy between the order of the enum values and their definition caused the test suite to fail spectacularly. Tablegen can streamline the process of generating the property definition table while at the same time guaranteeing that the enums stay in sync. That's exactly what this patch does. It adds a new tablegen file for the properties, building on top of the infrastructure that Raphael added recently for the command options. It also introduces two new tablegen backends: one for the property definitions and one for their corresponding enums. It might be worth mentioning that I generated most of the tablegen definitions from the existing property definitions, by adding a dump method to the struct. This seems both more efficient and less error prone that copying everything over by hand. Only Enum properties needed manual fixup for the EnumValues and DefaultEnumValue fields. Differential revision: https://reviews.llvm.org/D65185 llvm-svn: 367058
Diffstat (limited to 'lldb/utils')
-rw-r--r--lldb/utils/TableGen/CMakeLists.txt1
-rw-r--r--lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp173
-rw-r--r--lldb/utils/TableGen/LLDBTableGen.cpp28
-rw-r--r--lldb/utils/TableGen/LLDBTableGenBackends.h2
4 files changed, 196 insertions, 8 deletions
diff --git a/lldb/utils/TableGen/CMakeLists.txt b/lldb/utils/TableGen/CMakeLists.txt
index 45a5d366222..2f365d25af8 100644
--- a/lldb/utils/TableGen/CMakeLists.txt
+++ b/lldb/utils/TableGen/CMakeLists.txt
@@ -8,6 +8,7 @@ else()
add_tablegen(lldb-tblgen LLDB
LLDBOptionDefEmitter.cpp
+ LLDBPropertyDefEmitter.cpp
LLDBTableGen.cpp
)
set_target_properties(lldb-tblgen PROPERTIES FOLDER "LLDB tablegenning")
diff --git a/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp b/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp
new file mode 100644
index 00000000000..d295cbb4e08
--- /dev/null
+++ b/lldb/utils/TableGen/LLDBPropertyDefEmitter.cpp
@@ -0,0 +1,173 @@
+//===- LLDBPropertyDefEmitter.cpp -----------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// These tablegen backends emits LLDB's PropertyDefinition values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LLDBTableGenBackends.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringMatcher.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <map>
+#include <vector>
+
+using namespace llvm;
+
+/// Map of properties definitions to their associated records. Also makes sure
+/// our property definitions are sorted in a deterministic way.
+typedef std::map<std::string, std::vector<Record *>> RecordsByDefinition;
+
+/// Groups all properties by their definition.
+static RecordsByDefinition getPropertyList(std::vector<Record *> Properties) {
+ RecordsByDefinition result;
+ for (Record *Property : Properties)
+ result[Property->getValueAsString("Definition").str()].push_back(Property);
+ return result;
+}
+
+static void emitPropertyEnum(Record *Property, raw_ostream &OS) {
+ OS << "eProperty";
+ OS << Property->getName();
+ OS << ",\n";
+}
+
+static void emitProperty(Record *Property, raw_ostream &OS) {
+ OS << " {";
+
+ // Emit the property name.
+ OS << "\"" << Property->getValueAsString("Name") << "\"";
+ OS << ", ";
+
+ // Emit the property type.
+ OS << "OptionValue::eType";
+ OS << Property->getValueAsString("Type");
+ OS << ", ";
+
+ // Emit the property's global value.
+ OS << (Property->getValue("Global") ? "true" : "false");
+ OS << ", ";
+
+ bool hasDefaultUnsignedValue = Property->getValue("HasDefaultUnsignedValue");
+ bool hasDefaultEnumValue = Property->getValue("HasDefaultEnumValue");
+ bool hasDefaultStringValue = Property->getValue("HasDefaultStringValue");
+
+ // Guarantee that every property has a default value.
+ assert((hasDefaultUnsignedValue || hasDefaultEnumValue ||
+ hasDefaultStringValue) &&
+ "Property must have a default value");
+
+ // Guarantee that no property has both a default unsigned value and a default
+ // enum value, since they're bothed stored in the same field.
+ assert(!(hasDefaultUnsignedValue && hasDefaultEnumValue) &&
+ "Property cannot have both a unsigned and enum default value.");
+
+ // Emit the default uint value.
+ if (hasDefaultUnsignedValue) {
+ OS << std::to_string(Property->getValueAsInt("DefaultUnsignedValue"));
+ } else if (hasDefaultEnumValue) {
+ OS << Property->getValueAsString("DefaultEnumValue");
+ } else {
+ OS << "0";
+ }
+ OS << ", ";
+
+ // Emit the default string value.
+ if (hasDefaultStringValue) {
+ if (auto D = Property->getValue("DefaultStringValue")) {
+ OS << "\"";
+ llvm::printEscapedString(D->getValue()->getAsUnquotedString(), OS);
+ OS << "\"";
+ } else {
+ OS << "\"\"";
+ }
+ } else {
+ OS << "nullptr";
+ }
+ OS << ", ";
+
+ // Emit the enum values value.
+ if (Property->getValue("EnumValues"))
+ OS << Property->getValueAsString("EnumValues");
+ else
+ OS << "{}";
+ OS << ", ";
+
+ // Emit the property description.
+ if (auto D = Property->getValue("Description")) {
+ OS << "\"";
+ llvm::printEscapedString(D->getValue()->getAsUnquotedString(), OS);
+ OS << "\"";
+ } else {
+ OS << "\"\"";
+ }
+
+ OS << "},\n";
+}
+
+/// Emits all property initializers to the raw_ostream.
+static void emityProperties(std::string PropertyName,
+ std::vector<Record *> PropertyRecords,
+ raw_ostream &OS) {
+ // Generate the macro that the user needs to define before including the
+ // *.inc file.
+ std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName;
+ std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_');
+
+ // All options are in one file, so we need put them behind macros and ask the
+ // user to define the macro for the options that are needed.
+ OS << "// Property definitions for " << PropertyName << "\n";
+ OS << "#ifdef " << NeededMacro << "\n";
+ for (Record *R : PropertyRecords)
+ emitProperty(R, OS);
+ // We undefine the macro for the user like Clang's include files are doing it.
+ OS << "#undef " << NeededMacro << "\n";
+ OS << "#endif // " << PropertyName << " Property\n\n";
+}
+
+/// Emits all property initializers to the raw_ostream.
+static void emitPropertyEnum(std::string PropertyName,
+ std::vector<Record *> PropertyRecords,
+ raw_ostream &OS) {
+ // Generate the macro that the user needs to define before including the
+ // *.inc file.
+ std::string NeededMacro = "LLDB_PROPERTIES_" + PropertyName;
+ std::replace(NeededMacro.begin(), NeededMacro.end(), ' ', '_');
+
+ // All options are in one file, so we need put them behind macros and ask the
+ // user to define the macro for the options that are needed.
+ OS << "// Property enum cases for " << PropertyName << "\n";
+ OS << "#ifdef " << NeededMacro << "\n";
+ for (Record *R : PropertyRecords)
+ emitPropertyEnum(R, OS);
+ // We undefine the macro for the user like Clang's include files are doing it.
+ OS << "#undef " << NeededMacro << "\n";
+ OS << "#endif // " << PropertyName << " Property\n\n";
+}
+
+void lldb_private::EmitPropertyDefs(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Property definitions for LLDB.", OS);
+
+ std::vector<Record *> Properties =
+ Records.getAllDerivedDefinitions("Property");
+ for (auto &PropertyRecordPair : getPropertyList(Properties)) {
+ emityProperties(PropertyRecordPair.first, PropertyRecordPair.second, OS);
+ }
+}
+
+void lldb_private::EmitPropertyEnumDefs(RecordKeeper &Records,
+ raw_ostream &OS) {
+ emitSourceFileHeader("Property definition enum for LLDB.", OS);
+
+ std::vector<Record *> Properties =
+ Records.getAllDerivedDefinitions("Property");
+ for (auto &PropertyRecordPair : getPropertyList(Properties)) {
+ emitPropertyEnum(PropertyRecordPair.first, PropertyRecordPair.second, OS);
+ }
+}
diff --git a/lldb/utils/TableGen/LLDBTableGen.cpp b/lldb/utils/TableGen/LLDBTableGen.cpp
index 0a416d7d156..abb6589f0ca 100644
--- a/lldb/utils/TableGen/LLDBTableGen.cpp
+++ b/lldb/utils/TableGen/LLDBTableGen.cpp
@@ -25,16 +25,22 @@ enum ActionType {
PrintRecords,
DumpJSON,
GenOptionDefs,
+ GenPropertyDefs,
+ GenPropertyEnumDefs,
};
-static cl::opt<ActionType>
- Action(cl::desc("Action to perform:"),
- cl::values(clEnumValN(PrintRecords, "print-records",
- "Print all records to stdout (default)"),
- clEnumValN(DumpJSON, "dump-json",
- "Dump all records as machine-readable JSON"),
- clEnumValN(GenOptionDefs, "gen-lldb-option-defs",
- "Generate lldb option definitions")));
+static cl::opt<ActionType> Action(
+ cl::desc("Action to perform:"),
+ cl::values(clEnumValN(PrintRecords, "print-records",
+ "Print all records to stdout (default)"),
+ clEnumValN(DumpJSON, "dump-json",
+ "Dump all records as machine-readable JSON"),
+ clEnumValN(GenOptionDefs, "gen-lldb-option-defs",
+ "Generate lldb option definitions"),
+ clEnumValN(GenPropertyDefs, "gen-lldb-property-defs",
+ "Generate lldb property definitions"),
+ clEnumValN(GenPropertyEnumDefs, "gen-lldb-property-enum-defs",
+ "Generate lldb property enum definitions")));
static bool LLDBTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
switch (Action) {
@@ -47,6 +53,12 @@ static bool LLDBTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenOptionDefs:
EmitOptionDefs(Records, OS);
break;
+ case GenPropertyDefs:
+ EmitPropertyDefs(Records, OS);
+ break;
+ case GenPropertyEnumDefs:
+ EmitPropertyEnumDefs(Records, OS);
+ break;
}
return false;
}
diff --git a/lldb/utils/TableGen/LLDBTableGenBackends.h b/lldb/utils/TableGen/LLDBTableGenBackends.h
index 34e8bca0d7d..e5c3548f1c1 100644
--- a/lldb/utils/TableGen/LLDBTableGenBackends.h
+++ b/lldb/utils/TableGen/LLDBTableGenBackends.h
@@ -29,6 +29,8 @@ using llvm::RecordKeeper;
namespace lldb_private {
void EmitOptionDefs(RecordKeeper &RK, raw_ostream &OS);
+void EmitPropertyDefs(RecordKeeper &RK, raw_ostream &OS);
+void EmitPropertyEnumDefs(RecordKeeper &RK, raw_ostream &OS);
} // namespace lldb_private
OpenPOWER on IntegriCloud