mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
[TableGen] Add backend to generate command guide for tools using libOption.
For lldb and dsymutil, the command guide is essentially a copy of its help output generated by libOption. Making sure the two stay in sync is tedious and error prone. Given that we already generate the help from a tablegen file, we might as well generate the RST as well. This adds a tablegen backend for generating Sphinx/RST command guides from the tablegen file. Differential revision: https://reviews.llvm.org/D70610
This commit is contained in:
parent
3ba73f04c0
commit
70be4d27b2
@ -33,7 +33,9 @@ add_tablegen(llvm-tblgen LLVM
|
|||||||
InstrInfoEmitter.cpp
|
InstrInfoEmitter.cpp
|
||||||
InstrDocsEmitter.cpp
|
InstrDocsEmitter.cpp
|
||||||
IntrinsicEmitter.cpp
|
IntrinsicEmitter.cpp
|
||||||
|
OptEmitter.cpp
|
||||||
OptParserEmitter.cpp
|
OptParserEmitter.cpp
|
||||||
|
OptRSTEmitter.cpp
|
||||||
PredicateExpander.cpp
|
PredicateExpander.cpp
|
||||||
PseudoLoweringEmitter.cpp
|
PseudoLoweringEmitter.cpp
|
||||||
RISCVCompressInstEmitter.cpp
|
RISCVCompressInstEmitter.cpp
|
||||||
|
84
utils/TableGen/OptEmitter.cpp
Normal file
84
utils/TableGen/OptEmitter.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//===- OptEmitter.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 "OptEmitter.h"
|
||||||
|
#include "llvm/ADT/Twine.h"
|
||||||
|
#include "llvm/TableGen/Error.h"
|
||||||
|
#include "llvm/TableGen/Record.h"
|
||||||
|
#include <cctype>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
|
||||||
|
// Ordering on Info. The logic should match with the consumer-side function in
|
||||||
|
// llvm/Option/OptTable.h.
|
||||||
|
// FIXME: Make this take StringRefs instead of null terminated strings to
|
||||||
|
// simplify callers.
|
||||||
|
static int StrCmpOptionName(const char *A, const char *B) {
|
||||||
|
const char *X = A, *Y = B;
|
||||||
|
char a = tolower(*A), b = tolower(*B);
|
||||||
|
while (a == b) {
|
||||||
|
if (a == '\0')
|
||||||
|
return strcmp(A, B);
|
||||||
|
|
||||||
|
a = tolower(*++X);
|
||||||
|
b = tolower(*++Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == '\0') // A is a prefix of B.
|
||||||
|
return 1;
|
||||||
|
if (b == '\0') // B is a prefix of A.
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// Otherwise lexicographic.
|
||||||
|
return (a < b) ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CompareOptionRecords(Record *const *Av, Record *const *Bv) {
|
||||||
|
const Record *A = *Av;
|
||||||
|
const Record *B = *Bv;
|
||||||
|
|
||||||
|
// Sentinel options precede all others and are only ordered by precedence.
|
||||||
|
bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel");
|
||||||
|
bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel");
|
||||||
|
if (ASent != BSent)
|
||||||
|
return ASent ? -1 : 1;
|
||||||
|
|
||||||
|
// Compare options by name, unless they are sentinels.
|
||||||
|
if (!ASent)
|
||||||
|
if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").str().c_str(),
|
||||||
|
B->getValueAsString("Name").str().c_str()))
|
||||||
|
return Cmp;
|
||||||
|
|
||||||
|
if (!ASent) {
|
||||||
|
std::vector<StringRef> APrefixes = A->getValueAsListOfStrings("Prefixes");
|
||||||
|
std::vector<StringRef> BPrefixes = B->getValueAsListOfStrings("Prefixes");
|
||||||
|
|
||||||
|
for (std::vector<StringRef>::const_iterator APre = APrefixes.begin(),
|
||||||
|
AEPre = APrefixes.end(),
|
||||||
|
BPre = BPrefixes.begin(),
|
||||||
|
BEPre = BPrefixes.end();
|
||||||
|
APre != AEPre && BPre != BEPre; ++APre, ++BPre) {
|
||||||
|
if (int Cmp = StrCmpOptionName(APre->str().c_str(), BPre->str().c_str()))
|
||||||
|
return Cmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then by the kind precedence;
|
||||||
|
int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence");
|
||||||
|
int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence");
|
||||||
|
if (APrec == BPrec && A->getValueAsListOfStrings("Prefixes") ==
|
||||||
|
B->getValueAsListOfStrings("Prefixes")) {
|
||||||
|
PrintError(A->getLoc(), Twine("Option is equivalent to"));
|
||||||
|
PrintError(B->getLoc(), Twine("Other defined here"));
|
||||||
|
PrintFatalError("Equivalent Options found.");
|
||||||
|
}
|
||||||
|
return APrec < BPrec ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace llvm
|
16
utils/TableGen/OptEmitter.h
Normal file
16
utils/TableGen/OptEmitter.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
//===- OptEmitter.h - Helper for emitting options. --------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_UTILS_TABLEGEN_OPTEMITTER_H
|
||||||
|
#define LLVM_UTILS_TABLEGEN_OPTEMITTER_H
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
class Record;
|
||||||
|
int CompareOptionRecords(Record *const *Av, Record *const *Bv);
|
||||||
|
} // namespace llvm
|
||||||
|
#endif
|
@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "llvm/TableGen/Error.h"
|
#include "OptEmitter.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
#include "llvm/ADT/Twine.h"
|
#include "llvm/ADT/Twine.h"
|
||||||
@ -18,75 +18,6 @@
|
|||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
// Ordering on Info. The logic should match with the consumer-side function in
|
|
||||||
// llvm/Option/OptTable.h.
|
|
||||||
// FIXME: Mmake this take StringRefs instead of null terminated strings to
|
|
||||||
// simplify callers.
|
|
||||||
static int StrCmpOptionName(const char *A, const char *B) {
|
|
||||||
const char *X = A, *Y = B;
|
|
||||||
char a = tolower(*A), b = tolower(*B);
|
|
||||||
while (a == b) {
|
|
||||||
if (a == '\0')
|
|
||||||
return strcmp(A, B);
|
|
||||||
|
|
||||||
a = tolower(*++X);
|
|
||||||
b = tolower(*++Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a == '\0') // A is a prefix of B.
|
|
||||||
return 1;
|
|
||||||
if (b == '\0') // B is a prefix of A.
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
// Otherwise lexicographic.
|
|
||||||
return (a < b) ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CompareOptionRecords(Record *const *Av, Record *const *Bv) {
|
|
||||||
const Record *A = *Av;
|
|
||||||
const Record *B = *Bv;
|
|
||||||
|
|
||||||
// Sentinel options precede all others and are only ordered by precedence.
|
|
||||||
bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel");
|
|
||||||
bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel");
|
|
||||||
if (ASent != BSent)
|
|
||||||
return ASent ? -1 : 1;
|
|
||||||
|
|
||||||
// Compare options by name, unless they are sentinels.
|
|
||||||
if (!ASent)
|
|
||||||
if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").str().c_str(),
|
|
||||||
B->getValueAsString("Name").str().c_str()))
|
|
||||||
return Cmp;
|
|
||||||
|
|
||||||
if (!ASent) {
|
|
||||||
std::vector<StringRef> APrefixes = A->getValueAsListOfStrings("Prefixes");
|
|
||||||
std::vector<StringRef> BPrefixes = B->getValueAsListOfStrings("Prefixes");
|
|
||||||
|
|
||||||
for (std::vector<StringRef>::const_iterator APre = APrefixes.begin(),
|
|
||||||
AEPre = APrefixes.end(),
|
|
||||||
BPre = BPrefixes.begin(),
|
|
||||||
BEPre = BPrefixes.end();
|
|
||||||
APre != AEPre &&
|
|
||||||
BPre != BEPre;
|
|
||||||
++APre, ++BPre) {
|
|
||||||
if (int Cmp = StrCmpOptionName(APre->str().c_str(), BPre->str().c_str()))
|
|
||||||
return Cmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then by the kind precedence;
|
|
||||||
int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence");
|
|
||||||
int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence");
|
|
||||||
if (APrec == BPrec &&
|
|
||||||
A->getValueAsListOfStrings("Prefixes") ==
|
|
||||||
B->getValueAsListOfStrings("Prefixes")) {
|
|
||||||
PrintError(A->getLoc(), Twine("Option is equivalent to"));
|
|
||||||
PrintError(B->getLoc(), Twine("Other defined here"));
|
|
||||||
PrintFatalError("Equivalent Options found.");
|
|
||||||
}
|
|
||||||
return APrec < BPrec ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::string getOptionName(const Record &R) {
|
static const std::string getOptionName(const Record &R) {
|
||||||
// Use the record name unless EnumName is defined.
|
// Use the record name unless EnumName is defined.
|
||||||
if (isa<UnsetInit>(R.getValueInit("EnumName")))
|
if (isa<UnsetInit>(R.getValueInit("EnumName")))
|
||||||
|
88
utils/TableGen/OptRSTEmitter.cpp
Normal file
88
utils/TableGen/OptRSTEmitter.cpp
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===//
|
||||||
|
//
|
||||||
|
// 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 "OptEmitter.h"
|
||||||
|
#include "llvm/ADT/STLExtras.h"
|
||||||
|
#include "llvm/ADT/SmallString.h"
|
||||||
|
#include "llvm/ADT/Twine.h"
|
||||||
|
#include "llvm/TableGen/Error.h"
|
||||||
|
#include "llvm/TableGen/Record.h"
|
||||||
|
#include "llvm/TableGen/TableGenBackend.h"
|
||||||
|
#include <cctype>
|
||||||
|
#include <cstring>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
/// OptParserEmitter - This tablegen backend takes an input .td file
|
||||||
|
/// describing a list of options and emits a RST man page.
|
||||||
|
namespace llvm {
|
||||||
|
void EmitOptRST(RecordKeeper &Records, raw_ostream &OS) {
|
||||||
|
llvm::StringMap<std::vector<Record *>> OptionsByGroup;
|
||||||
|
std::vector<Record *> OptionsWithoutGroup;
|
||||||
|
|
||||||
|
// Get the options.
|
||||||
|
std::vector<Record *> Opts = Records.getAllDerivedDefinitions("Option");
|
||||||
|
array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords);
|
||||||
|
|
||||||
|
// Get the option groups.
|
||||||
|
const std::vector<Record *> &Groups =
|
||||||
|
Records.getAllDerivedDefinitions("OptionGroup");
|
||||||
|
for (unsigned i = 0, e = Groups.size(); i != e; ++i) {
|
||||||
|
const Record &R = *Groups[i];
|
||||||
|
OptionsByGroup.try_emplace(R.getValueAsString("Name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map options to their group.
|
||||||
|
for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
|
||||||
|
const Record &R = *Opts[i];
|
||||||
|
const ListInit *GroupFlags = nullptr;
|
||||||
|
if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
|
||||||
|
GroupFlags = DI->getDef()->getValueAsListInit("Flags");
|
||||||
|
OptionsByGroup[DI->getDef()->getValueAsString("Name")].push_back(Opts[i]);
|
||||||
|
} else {
|
||||||
|
OptionsByGroup["options"].push_back(Opts[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print options under their group.
|
||||||
|
for (const auto &KV : OptionsByGroup) {
|
||||||
|
std::string GroupName = KV.getKey().upper();
|
||||||
|
OS << GroupName << '\n';
|
||||||
|
OS << std::string(GroupName.size(), '-') << '\n';
|
||||||
|
OS << '\n';
|
||||||
|
|
||||||
|
for (Record *R : KV.getValue()) {
|
||||||
|
OS << ".. option:: ";
|
||||||
|
|
||||||
|
// Print the prefix.
|
||||||
|
std::vector<StringRef> Prefixes = R->getValueAsListOfStrings("Prefixes");
|
||||||
|
if (!Prefixes.empty())
|
||||||
|
OS << Prefixes[0];
|
||||||
|
|
||||||
|
// Print the option name.
|
||||||
|
OS << R->getValueAsString("Name");
|
||||||
|
|
||||||
|
// Print the meta-variable.
|
||||||
|
if (!isa<UnsetInit>(R->getValueInit("MetaVarName"))) {
|
||||||
|
OS << '=';
|
||||||
|
OS.write_escaped(R->getValueAsString("MetaVarName"));
|
||||||
|
}
|
||||||
|
|
||||||
|
OS << "\n\n";
|
||||||
|
|
||||||
|
// The option help text.
|
||||||
|
if (!isa<UnsetInit>(R->getValueInit("HelpText"))) {
|
||||||
|
OS << ' ';
|
||||||
|
OS.write_escaped(R->getValueAsString("HelpText"));
|
||||||
|
OS << "\n\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end namespace llvm
|
@ -45,6 +45,7 @@ enum ActionType {
|
|||||||
PrintEnums,
|
PrintEnums,
|
||||||
PrintSets,
|
PrintSets,
|
||||||
GenOptParserDefs,
|
GenOptParserDefs,
|
||||||
|
GenOptRST,
|
||||||
GenCTags,
|
GenCTags,
|
||||||
GenAttributes,
|
GenAttributes,
|
||||||
GenSearchableTables,
|
GenSearchableTables,
|
||||||
@ -110,6 +111,7 @@ cl::opt<ActionType> Action(
|
|||||||
"Print expanded sets for testing DAG exprs"),
|
"Print expanded sets for testing DAG exprs"),
|
||||||
clEnumValN(GenOptParserDefs, "gen-opt-parser-defs",
|
clEnumValN(GenOptParserDefs, "gen-opt-parser-defs",
|
||||||
"Generate option definitions"),
|
"Generate option definitions"),
|
||||||
|
clEnumValN(GenOptRST, "gen-opt-rst", "Generate option RST"),
|
||||||
clEnumValN(GenCTags, "gen-ctags", "Generate ctags-compatible index"),
|
clEnumValN(GenCTags, "gen-ctags", "Generate ctags-compatible index"),
|
||||||
clEnumValN(GenAttributes, "gen-attrs", "Generate attributes"),
|
clEnumValN(GenAttributes, "gen-attrs", "Generate attributes"),
|
||||||
clEnumValN(GenSearchableTables, "gen-searchable-tables",
|
clEnumValN(GenSearchableTables, "gen-searchable-tables",
|
||||||
@ -126,8 +128,7 @@ cl::opt<ActionType> Action(
|
|||||||
"Generate registers bank descriptions"),
|
"Generate registers bank descriptions"),
|
||||||
clEnumValN(GenExegesis, "gen-exegesis",
|
clEnumValN(GenExegesis, "gen-exegesis",
|
||||||
"Generate llvm-exegesis tables"),
|
"Generate llvm-exegesis tables"),
|
||||||
clEnumValN(GenAutomata, "gen-automata",
|
clEnumValN(GenAutomata, "gen-automata", "Generate generic automata")));
|
||||||
"Generate generic automata")));
|
|
||||||
|
|
||||||
cl::OptionCategory PrintEnumsCat("Options for -print-enums");
|
cl::OptionCategory PrintEnumsCat("Options for -print-enums");
|
||||||
cl::opt<std::string> Class("class", cl::desc("Print Enum list for this class"),
|
cl::opt<std::string> Class("class", cl::desc("Print Enum list for this class"),
|
||||||
@ -204,6 +205,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
|
|||||||
case GenOptParserDefs:
|
case GenOptParserDefs:
|
||||||
EmitOptParser(Records, OS);
|
EmitOptParser(Records, OS);
|
||||||
break;
|
break;
|
||||||
|
case GenOptRST:
|
||||||
|
EmitOptRST(Records, OS);
|
||||||
|
break;
|
||||||
case PrintEnums:
|
case PrintEnums:
|
||||||
{
|
{
|
||||||
for (Record *Rec : Records.getAllDerivedDefinitions(Class))
|
for (Record *Rec : Records.getAllDerivedDefinitions(Class))
|
||||||
|
@ -81,6 +81,7 @@ void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS);
|
|||||||
void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS);
|
void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS);
|
||||||
void EmitMapTable(RecordKeeper &RK, raw_ostream &OS);
|
void EmitMapTable(RecordKeeper &RK, raw_ostream &OS);
|
||||||
void EmitOptParser(RecordKeeper &RK, raw_ostream &OS);
|
void EmitOptParser(RecordKeeper &RK, raw_ostream &OS);
|
||||||
|
void EmitOptRST(RecordKeeper &RK, raw_ostream &OS);
|
||||||
void EmitCTags(RecordKeeper &RK, raw_ostream &OS);
|
void EmitCTags(RecordKeeper &RK, raw_ostream &OS);
|
||||||
void EmitAttributes(RecordKeeper &RK, raw_ostream &OS);
|
void EmitAttributes(RecordKeeper &RK, raw_ostream &OS);
|
||||||
void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS);
|
void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS);
|
||||||
|
Loading…
Reference in New Issue
Block a user