[OptTable] Precompute OptTable prefixes union table through tablegen

This avoid rediscovering this table when reading each options, providing
a sensible 2% speedup when processing and empty file, and a measurable
speedup on typical workloads, see:

This is optional, the legacy, on-the-fly, approach can still be used
through the GenericOptTable class, while the new one is used through
PrecomputedOptTable.

https://llvm-compile-time-tracker.com/compare.php?from=4da6cb3202817ee2897d6b690e4af950459caea4&to=19a492b704e8f5c1dea120b9c0d3859bd78796be&stat=instructions:u

Differential Revision: https://reviews.llvm.org/D140800
This commit is contained in:
serge-sans-paille 2022-12-30 08:32:59 +01:00
parent bbe463d6ba
commit 07bb29d8ff
No known key found for this signature in database
GPG Key ID: 7B24DA8C9551659F
38 changed files with 256 additions and 143 deletions
clang
lib/Driver
tools/clang-linker-wrapper
lld
lldb/tools
llvm
include/llvm/Option
lib
ExecutionEngine/JITLink
Option
ToolDrivers
llvm-dlltool
llvm-lib
tools
dsymutil
llvm-cvtres
llvm-cxxfilt
llvm-dwarfutil
llvm-ifs
llvm-lipo
llvm-ml
llvm-mt
llvm-nm
llvm-objcopy
llvm-objdump
llvm-rc
llvm-readobj
llvm-size
llvm-strings
llvm-symbolizer
llvm-tli-checker
unittests/Option
utils/TableGen

@ -27,6 +27,14 @@ using namespace llvm::opt;
#include "clang/Driver/Options.inc"
#undef PREFIX
static constexpr const llvm::StringLiteral PrefixTable_init[] =
#define PREFIX_UNION(VALUES) VALUES
#include "clang/Driver/Options.inc"
#undef PREFIX_UNION
;
static constexpr const llvm::ArrayRef<llvm::StringLiteral>
PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1);
static constexpr OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
@ -38,12 +46,10 @@ static constexpr OptTable::Info InfoTable[] = {
namespace {
class DriverOptTable : public OptTable {
class DriverOptTable : public PrecomputedOptTable {
public:
DriverOptTable()
: OptTable(InfoTable) {}
DriverOptTable() : PrecomputedOptTable(InfoTable, PrefixTable) {}
};
}
const llvm::opt::OptTable &clang::driver::getDriverOptTable() {

@ -23,6 +23,7 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CodeGen.h"

@ -138,9 +138,9 @@ static constexpr OptTable::Info InfoTable[] = {
#undef OPTION
};
class WrapperOptTable : public opt::OptTable {
class WrapperOptTable : public opt::GenericOptTable {
public:
WrapperOptTable() : OptTable(InfoTable) {}
WrapperOptTable() : opt::GenericOptTable(InfoTable) {}
};
const OptTable &getOptTable() {

@ -33,7 +33,7 @@ using llvm::COFF::MachineTypes;
using llvm::COFF::WindowsSubsystem;
using std::optional;
class COFFOptTable : public llvm::opt::OptTable {
class COFFOptTable : public llvm::opt::GenericOptTable {
public:
COFFOptTable();
};

@ -794,7 +794,7 @@ static constexpr llvm::opt::OptTable::Info infoTable[] = {
#undef OPTION
};
COFFOptTable::COFFOptTable() : OptTable(infoTable, true) {}
COFFOptTable::COFFOptTable() : GenericOptTable(infoTable, true) {}
// Set color diagnostics according to --color-diagnostics={auto,always,never}
// or --no-color-diagnostics flags.

@ -16,7 +16,7 @@
namespace lld::elf {
// Parses command line options.
class ELFOptTable : public llvm::opt::OptTable {
class ELFOptTable : public llvm::opt::GenericOptTable {
public:
ELFOptTable();
llvm::opt::InputArgList parse(ArrayRef<const char *> argv);

@ -50,7 +50,7 @@ static constexpr opt::OptTable::Info optInfo[] = {
#undef OPTION
};
ELFOptTable::ELFOptTable() : OptTable(optInfo) {}
ELFOptTable::ELFOptTable() : GenericOptTable(optInfo) {}
// Set color diagnostics according to --color-diagnostics={auto,always,never}
// or --no-color-diagnostics flags.

@ -25,7 +25,7 @@ namespace lld::macho {
class DylibFile;
class InputFile;
class MachOOptTable : public llvm::opt::OptTable {
class MachOOptTable : public llvm::opt::GenericOptTable {
public:
MachOOptTable();
llvm::opt::InputArgList parse(ArrayRef<const char *> argv);

@ -51,7 +51,7 @@ static constexpr OptTable::Info optInfo[] = {
#undef OPTION
};
MachOOptTable::MachOOptTable() : OptTable(optInfo) {}
MachOOptTable::MachOOptTable() : GenericOptTable(optInfo) {}
// Set color diagnostics according to --color-diagnostics={auto,always,never}
// or --no-color-diagnostics flags.

@ -79,9 +79,9 @@ static constexpr opt::OptTable::Info infoTable[] = {
};
namespace {
class MinGWOptTable : public opt::OptTable {
class MinGWOptTable : public opt::GenericOptTable {
public:
MinGWOptTable() : OptTable(infoTable, false) {}
MinGWOptTable() : opt::GenericOptTable(infoTable, false) {}
opt::InputArgList parse(ArrayRef<const char *> argv);
};
} // namespace

@ -120,9 +120,9 @@ static constexpr opt::OptTable::Info optInfo[] = {
};
namespace {
class WasmOptTable : public llvm::opt::OptTable {
class WasmOptTable : public opt::GenericOptTable {
public:
WasmOptTable() : OptTable(optInfo) {}
WasmOptTable() : opt::GenericOptTable(optInfo) {}
opt::InputArgList parse(ArrayRef<const char *> argv);
};
} // namespace

@ -78,9 +78,9 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class LLDBOptTable : public opt::OptTable {
class LLDBOptTable : public opt::GenericOptTable {
public:
LLDBOptTable() : OptTable(InfoTable) {}
LLDBOptTable() : opt::GenericOptTable(InfoTable) {}
};
} // namespace

@ -297,9 +297,9 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class LLGSOptTable : public opt::OptTable {
class LLGSOptTable : public opt::GenericOptTable {
public:
LLGSOptTable() : OptTable(InfoTable) {}
LLGSOptTable() : opt::GenericOptTable(InfoTable) {}
void PrintHelp(llvm::StringRef Name) {
std::string Usage =

@ -96,9 +96,9 @@ static constexpr llvm::opt::OptTable::Info InfoTable[] = {
#include "Options.inc"
#undef OPTION
};
class LLDBVSCodeOptTable : public llvm::opt::OptTable {
class LLDBVSCodeOptTable : public llvm::opt::GenericOptTable {
public:
LLDBVSCodeOptTable() : OptTable(InfoTable, true) {}
LLDBVSCodeOptTable() : llvm::opt::GenericOptTable(InfoTable, true) {}
};
typedef void (*RequestCallback)(const llvm::json::Object &command);

@ -12,7 +12,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Option/OptSpecifier.h"
#include "llvm/Support/StringSaver.h"
#include <cassert>
@ -68,14 +67,17 @@ private:
unsigned InputOptionID = 0;
unsigned UnknownOptionID = 0;
protected:
/// The index of the first option which can be parsed (i.e., is not a
/// special option like 'input' or 'unknown', and is not an option group).
unsigned FirstSearchableIndex = 0;
/// The union of the first element of all option prefixes.
SmallString<8> PrefixChars;
/// The union of all option prefixes. If an argument does not begin with
/// one of these, it is an input.
StringSet<> PrefixesUnion;
SmallString<8> PrefixChars;
virtual ArrayRef<StringLiteral> getPrefixesUnion() const = 0;
private:
const Info &getInfo(OptSpecifier Opt) const {
@ -88,10 +90,15 @@ private:
unsigned &Index) const;
protected:
/// Initialize OptTable using Tablegen'ed OptionInfos. Child class must
/// manually call \c buildPrefixChars once they are fully constructed.
OptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase = false);
/// Build (or rebuild) the PrefixChars member.
void buildPrefixChars();
public:
~OptTable();
virtual ~OptTable();
/// Return the total number of option classes.
unsigned getNumOptions() const { return OptionInfos.size(); }
@ -246,6 +253,32 @@ public:
bool ShowHidden = false, bool ShowAllAliases = false) const;
};
/// Specialization of OptTable
class GenericOptTable : public OptTable {
SmallVector<StringLiteral> PrefixesUnionBuffer;
protected:
GenericOptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase = false);
ArrayRef<StringLiteral> getPrefixesUnion() const final {
return PrefixesUnionBuffer;
}
};
class PrecomputedOptTable : public OptTable {
ArrayRef<StringLiteral> PrefixesUnion;
protected:
PrecomputedOptTable(ArrayRef<Info> OptionInfos,
ArrayRef<StringLiteral> PrefixesTable,
bool IgnoreCase = false)
: OptTable(OptionInfos, IgnoreCase), PrefixesUnion(PrefixesTable) {
buildPrefixChars();
}
ArrayRef<StringLiteral> getPrefixesUnion() const final {
return PrefixesUnion;
}
};
} // end namespace opt
} // end namespace llvm

@ -27,6 +27,14 @@ using namespace jitlink;
#include "COFFOptions.inc"
#undef PREFIX
static constexpr const StringLiteral PrefixTable_init[] =
#define PREFIX_UNION(VALUES) VALUES
#include "COFFOptions.inc"
#undef PREFIX_UNION
;
static constexpr const ArrayRef<StringLiteral>
PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1);
// Create table mapping all options defined in COFFOptions.td
static constexpr opt::OptTable::Info infoTable[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
@ -46,9 +54,9 @@ static constexpr opt::OptTable::Info infoTable[] = {
#undef OPTION
};
class COFFOptTable : public opt::OptTable {
class COFFOptTable : public opt::PrecomputedOptTable {
public:
COFFOptTable() : OptTable(infoTable, true) {}
COFFOptTable() : PrecomputedOptTable(infoTable, PrefixTable, true) {}
};
static COFFOptTable optTable;

@ -9,7 +9,6 @@
#include "llvm/Option/OptTable.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptSpecifier.h"
@ -23,6 +22,7 @@
#include <cctype>
#include <cstring>
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>
@ -125,16 +125,13 @@ OptTable::OptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase)
}
}
#endif
}
// Build prefixes.
for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions() + 1;
i != e; ++i) {
const auto &P = getInfo(i).Prefixes;
PrefixesUnion.insert(P.begin(), P.end());
}
void OptTable::buildPrefixChars() {
assert(PrefixChars.empty() && "rebuilding a non-empty prefix char");
// Build prefix chars.
for (const StringRef &Prefix : PrefixesUnion.keys()) {
for (const StringLiteral &Prefix : getPrefixesUnion()) {
for (char C : Prefix)
if (!is_contained(PrefixChars, C))
PrefixChars.push_back(C);
@ -151,10 +148,10 @@ const Option OptTable::getOption(OptSpecifier Opt) const {
return Option(&getInfo(id), this);
}
static bool isInput(const StringSet<> &Prefixes, StringRef Arg) {
static bool isInput(const ArrayRef<StringLiteral> &Prefixes, StringRef Arg) {
if (Arg == "-")
return true;
for (const StringRef &Prefix : Prefixes.keys())
for (const StringRef &Prefix : Prefixes)
if (Arg.startswith(Prefix))
return false;
return true;
@ -236,6 +233,9 @@ unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
// Consider each [option prefix + option name] pair as a candidate, finding
// the closest match.
unsigned BestDistance = UINT_MAX;
SmallString<16> Candidate;
SmallString<16> NormalizedName;
for (const Info &CandidateInfo :
ArrayRef<Info>(OptionInfos).drop_front(FirstSearchableIndex)) {
StringRef CandidateName = CandidateInfo.Name;
@ -243,7 +243,7 @@ unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
// We can eliminate some option prefix/name pairs as candidates right away:
// * Ignore option candidates with empty names, such as "--", or names
// that do not meet the minimum length.
if (CandidateName.empty() || CandidateName.size() < MinimumLength)
if (CandidateName.size() < MinimumLength)
continue;
// * If FlagsToInclude were specified, ignore options that don't include
@ -262,26 +262,25 @@ unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
// Now check if the candidate ends with a character commonly used when
// delimiting an option from its value, such as '=' or ':'. If it does,
// attempt to split the given option based on that delimiter.
StringRef LHS, RHS;
char Last = CandidateName.back();
bool CandidateHasDelimiter = Last == '=' || Last == ':';
std::string NormalizedName = std::string(Option);
StringRef RHS;
if (CandidateHasDelimiter) {
std::tie(LHS, RHS) = Option.split(Last);
NormalizedName = std::string(LHS);
if (Option.find(Last) == LHS.size())
std::tie(NormalizedName, RHS) = Option.split(Last);
if (Option.find(Last) == NormalizedName.size())
NormalizedName += Last;
}
} else
NormalizedName = Option;
// Consider each possible prefix for each candidate to find the most
// appropriate one. For example, if a user asks for "--helm", suggest
// "--help" over "-help".
for (auto CandidatePrefix : CandidateInfo.Prefixes) {
std::string Candidate = (CandidatePrefix + CandidateName).str();
StringRef CandidateRef = Candidate;
unsigned Distance =
CandidateRef.edit_distance(NormalizedName, /*AllowReplacements=*/true,
/*MaxEditDistance=*/BestDistance);
Candidate = CandidatePrefix;
Candidate += CandidateName;
unsigned Distance = StringRef(Candidate).edit_distance(
NormalizedName, /*AllowReplacements=*/true,
/*MaxEditDistance=*/BestDistance);
if (RHS.empty() && CandidateHasDelimiter) {
// The Candidate ends with a = or : delimiter, but the option passed in
// didn't contain the delimiter (or doesn't have anything after it).
@ -310,7 +309,7 @@ std::unique_ptr<Arg> OptTable::parseOneArgGrouped(InputArgList &Args,
// itself.
const char *CStr = Args.getArgString(Index);
StringRef Str(CStr);
if (isInput(PrefixesUnion, Str))
if (isInput(getPrefixesUnion(), Str))
return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++, CStr);
const Info *End = OptionInfos.data() + OptionInfos.size();
@ -375,7 +374,7 @@ std::unique_ptr<Arg> OptTable::ParseOneArg(const ArgList &Args, unsigned &Index,
// Anything that doesn't start with PrefixesUnion is an input, as is '-'
// itself.
if (isInput(PrefixesUnion, Str))
if (isInput(getPrefixesUnion(), Str))
return std::make_unique<Arg>(getOption(InputOptionID), Str, Index++,
Str.data());
@ -653,3 +652,13 @@ void OptTable::printHelp(raw_ostream &OS, const char *Usage, const char *Title,
OS.flush();
}
GenericOptTable::GenericOptTable(ArrayRef<Info> OptionInfos, bool IgnoreCase)
: OptTable(OptionInfos, IgnoreCase) {
std::set<StringLiteral> TmpPrefixesUnion;
for (auto const &Info : OptionInfos.drop_front(FirstSearchableIndex))
TmpPrefixesUnion.insert(Info.Prefixes.begin(), Info.Prefixes.end());
PrefixesUnionBuffer.append(TmpPrefixesUnion.begin(), TmpPrefixesUnion.end());
buildPrefixChars();
}

@ -52,9 +52,9 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class DllOptTable : public llvm::opt::OptTable {
class DllOptTable : public opt::GenericOptTable {
public:
DllOptTable() : OptTable(InfoTable, false) {}
DllOptTable() : opt::GenericOptTable(InfoTable, false) {}
};
// Opens a file. Path has to be resolved already.

@ -56,11 +56,10 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class LibOptTable : public opt::OptTable {
class LibOptTable : public opt::GenericOptTable {
public:
LibOptTable() : OptTable(InfoTable, true) {}
LibOptTable() : opt::GenericOptTable(InfoTable, true) {}
};
}
static std::string getDefaultOutputPath(const NewArchiveMember &FirstMember) {

@ -82,9 +82,9 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class DsymutilOptTable : public opt::OptTable {
class DsymutilOptTable : public opt::GenericOptTable {
public:
DsymutilOptTable() : OptTable(InfoTable) {}
DsymutilOptTable() : opt::GenericOptTable(InfoTable) {}
};
} // namespace

@ -63,9 +63,9 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class CvtResOptTable : public opt::OptTable {
class CvtResOptTable : public opt::GenericOptTable {
public:
CvtResOptTable() : OptTable(InfoTable, true) {}
CvtResOptTable() : opt::GenericOptTable(InfoTable, true) {}
};
}

@ -51,9 +51,11 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class CxxfiltOptTable : public opt::OptTable {
class CxxfiltOptTable : public opt::GenericOptTable {
public:
CxxfiltOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
CxxfiltOptTable() : opt::GenericOptTable(InfoTable) {
setGroupedShortOptions(true);
}
};
} // namespace

@ -59,9 +59,9 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class DwarfutilOptTable : public opt::OptTable {
class DwarfutilOptTable : public opt::GenericOptTable {
public:
DwarfutilOptTable() : OptTable(InfoTable) {}
DwarfutilOptTable() : opt::GenericOptTable(InfoTable) {}
};
} // namespace

@ -79,9 +79,11 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class IFSOptTable : public opt::OptTable {
class IFSOptTable : public opt::GenericOptTable {
public:
IFSOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
IFSOptTable() : opt::GenericOptTable(InfoTable) {
setGroupedShortOptions(true);
}
};
struct DriverConfig {

@ -93,9 +93,9 @@ static constexpr opt::OptTable::Info LipoInfoTable[] = {
};
} // namespace lipo
class LipoOptTable : public opt::OptTable {
class LipoOptTable : public opt::GenericOptTable {
public:
LipoOptTable() : OptTable(lipo::LipoInfoTable) {}
LipoOptTable() : opt::GenericOptTable(lipo::LipoInfoTable) {}
};
enum class LipoAction {

@ -79,9 +79,9 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class MLOptTable : public opt::OptTable {
class MLOptTable : public opt::GenericOptTable {
public:
MLOptTable() : OptTable(InfoTable, /*IgnoreCase=*/false) {}
MLOptTable() : opt::GenericOptTable(InfoTable, /*IgnoreCase=*/false) {}
};
} // namespace

@ -60,9 +60,9 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class CvtResOptTable : public opt::OptTable {
class CvtResOptTable : public opt::GenericOptTable {
public:
CvtResOptTable() : OptTable(InfoTable, true) {}
CvtResOptTable() : opt::GenericOptTable(InfoTable, true) {}
};
} // namespace

@ -83,9 +83,11 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class NmOptTable : public opt::OptTable {
class NmOptTable : public opt::GenericOptTable {
public:
NmOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
NmOptTable() : opt::GenericOptTable(InfoTable) {
setGroupedShortOptions(true);
}
};
enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols };

@ -56,9 +56,9 @@ static constexpr opt::OptTable::Info ObjcopyInfoTable[] = {
};
} // namespace objcopy_opt
class ObjcopyOptTable : public opt::OptTable {
class ObjcopyOptTable : public opt::GenericOptTable {
public:
ObjcopyOptTable() : OptTable(objcopy_opt::ObjcopyInfoTable) {
ObjcopyOptTable() : opt::GenericOptTable(objcopy_opt::ObjcopyInfoTable) {
setGroupedShortOptions(true);
}
};
@ -101,10 +101,10 @@ static constexpr opt::OptTable::Info InstallNameToolInfoTable[] = {
};
} // namespace install_name_tool
class InstallNameToolOptTable : public opt::OptTable {
class InstallNameToolOptTable : public opt::GenericOptTable {
public:
InstallNameToolOptTable()
: OptTable(install_name_tool::InstallNameToolInfoTable) {}
: GenericOptTable(install_name_tool::InstallNameToolInfoTable) {}
};
enum BitcodeStripID {
@ -145,9 +145,10 @@ static constexpr opt::OptTable::Info BitcodeStripInfoTable[] = {
};
} // namespace bitcode_strip
class BitcodeStripOptTable : public opt::OptTable {
class BitcodeStripOptTable : public opt::GenericOptTable {
public:
BitcodeStripOptTable() : OptTable(bitcode_strip::BitcodeStripInfoTable) {}
BitcodeStripOptTable()
: opt::GenericOptTable(bitcode_strip::BitcodeStripInfoTable) {}
};
enum StripID {
@ -179,9 +180,9 @@ static constexpr opt::OptTable::Info StripInfoTable[] = {
};
} // namespace strip
class StripOptTable : public opt::OptTable {
class StripOptTable : public opt::GenericOptTable {
public:
StripOptTable() : OptTable(strip::StripInfoTable) {
StripOptTable() : GenericOptTable(strip::StripInfoTable) {
setGroupedShortOptions(true);
}
};

@ -97,18 +97,19 @@ using namespace llvm::opt;
namespace {
class CommonOptTable : public opt::OptTable {
class CommonOptTable : public opt::GenericOptTable {
public:
CommonOptTable(ArrayRef<Info> OptionInfos, const char *Usage,
const char *Description)
: OptTable(OptionInfos), Usage(Usage), Description(Description) {
: opt::GenericOptTable(OptionInfos), Usage(Usage),
Description(Description) {
setGroupedShortOptions(true);
}
void printHelp(StringRef Argv0, bool ShowHidden = false) const {
Argv0 = sys::path::filename(Argv0);
opt::OptTable::printHelp(outs(), (Argv0 + Usage).str().c_str(), Description,
ShowHidden, ShowHidden);
opt::GenericOptTable::printHelp(outs(), (Argv0 + Usage).str().c_str(),
Description, ShowHidden, ShowHidden);
// TODO Replace this with OptTable API once it adds extrahelp support.
outs() << "\nPass @FILE as argument to read options from FILE.\n";
}

@ -76,9 +76,9 @@ static constexpr opt::OptTable::Info InfoTable[] = {
};
} // namespace rc_opt
class RcOptTable : public opt::OptTable {
class RcOptTable : public opt::GenericOptTable {
public:
RcOptTable() : OptTable(rc_opt::InfoTable, /* IgnoreCase = */ true) {}
RcOptTable() : GenericOptTable(rc_opt::InfoTable, /* IgnoreCase = */ true) {}
};
enum Windres_ID {
@ -110,10 +110,10 @@ static constexpr opt::OptTable::Info InfoTable[] = {
};
} // namespace windres_opt
class WindresOptTable : public opt::OptTable {
class WindresOptTable : public opt::GenericOptTable {
public:
WindresOptTable()
: OptTable(windres_opt::InfoTable, /* IgnoreCase = */ false) {}
: GenericOptTable(windres_opt::InfoTable, /* IgnoreCase = */ false) {}
};
static ExitOnError ExitOnErr;

@ -80,9 +80,11 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class ReadobjOptTable : public opt::OptTable {
class ReadobjOptTable : public opt::GenericOptTable {
public:
ReadobjOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
ReadobjOptTable() : opt::GenericOptTable(InfoTable) {
setGroupedShortOptions(true);
}
};
enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols };

@ -66,9 +66,9 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class SizeOptTable : public opt::OptTable {
class SizeOptTable : public opt::GenericOptTable {
public:
SizeOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
SizeOptTable() : GenericOptTable(InfoTable) { setGroupedShortOptions(true); }
};
enum OutputFormatTy { berkeley, sysv, darwin };

@ -58,9 +58,11 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class StringsOptTable : public opt::OptTable {
class StringsOptTable : public opt::GenericOptTable {
public:
StringsOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
StringsOptTable() : GenericOptTable(InfoTable) {
setGroupedShortOptions(true);
}
};
} // namespace

@ -75,9 +75,9 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class SymbolizerOptTable : public opt::OptTable {
class SymbolizerOptTable : public opt::GenericOptTable {
public:
SymbolizerOptTable() : OptTable(InfoTable) {
SymbolizerOptTable() : GenericOptTable(InfoTable) {
setGroupedShortOptions(true);
}
};

@ -54,9 +54,9 @@ static constexpr opt::OptTable::Info InfoTable[] = {
#undef OPTION
};
class TLICheckerOptTable : public opt::OptTable {
class TLICheckerOptTable : public opt::GenericOptTable {
public:
TLICheckerOptTable() : OptTable(InfoTable) {}
TLICheckerOptTable() : GenericOptTable(InfoTable) {}
};
} // end anonymous namespace

@ -32,6 +32,14 @@ enum ID {
#include "Opts.inc"
#undef PREFIX
static constexpr const StringLiteral PrefixTable_init[] =
#define PREFIX_UNION(VALUES) VALUES
#include "Opts.inc"
#undef PREFIX_UNION
;
static constexpr const ArrayRef<StringLiteral>
PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1);
enum OptionFlags {
OptFlag1 = (1 << 4),
OptFlag2 = (1 << 5),
@ -48,10 +56,16 @@ static constexpr OptTable::Info InfoTable[] = {
};
namespace {
class TestOptTable : public OptTable {
class TestOptTable : public GenericOptTable {
public:
TestOptTable(bool IgnoreCase = false)
: OptTable(InfoTable, IgnoreCase) {}
: GenericOptTable(InfoTable, IgnoreCase) {}
};
class TestPrecomputedOptTable : public PrecomputedOptTable {
public:
TestPrecomputedOptTable(bool IgnoreCase = false)
: PrecomputedOptTable(InfoTable, PrefixTable, IgnoreCase) {}
};
}
@ -67,8 +81,20 @@ const char *Args[] = {
"-Gchuu", "2"
};
TEST(Option, OptionParsing) {
TestOptTable T;
// Test fixture
template <typename T> class OptTableTest : public ::testing::Test {};
template <typename T> class DISABLED_OptTableTest : public ::testing::Test {};
// Test both precomputed and computed OptTables with the same suite of tests.
using OptTableTestTypes =
::testing::Types<TestOptTable, TestPrecomputedOptTable>;
TYPED_TEST_SUITE(OptTableTest, OptTableTestTypes, );
TYPED_TEST_SUITE(DISABLED_OptTableTest, OptTableTestTypes, );
TYPED_TEST(OptTableTest, OptionParsing) {
TypeParam T;
unsigned MAI, MAC;
InputArgList AL = T.ParseArgs(Args, MAI, MAC);
@ -114,8 +140,8 @@ TEST(Option, OptionParsing) {
EXPECT_EQ("desu", StringRef(ASL[1]));
}
TEST(Option, ParseWithFlagExclusions) {
TestOptTable T;
TYPED_TEST(OptTableTest, ParseWithFlagExclusions) {
TypeParam T;
unsigned MAI, MAC;
// Exclude flag3 to avoid parsing as OPT_SLASH_C.
@ -142,8 +168,8 @@ TEST(Option, ParseWithFlagExclusions) {
EXPECT_EQ("bar", AL.getLastArgValue(OPT_C));
}
TEST(Option, ParseAliasInGroup) {
TestOptTable T;
TYPED_TEST(OptTableTest, ParseAliasInGroup) {
TypeParam T;
unsigned MAI, MAC;
const char *MyArgs[] = { "-I" };
@ -151,8 +177,8 @@ TEST(Option, ParseAliasInGroup) {
EXPECT_TRUE(AL.hasArg(OPT_H));
}
TEST(Option, AliasArgs) {
TestOptTable T;
TYPED_TEST(OptTableTest, AliasArgs) {
TypeParam T;
unsigned MAI, MAC;
const char *MyArgs[] = { "-J", "-Joo" };
@ -162,8 +188,8 @@ TEST(Option, AliasArgs) {
EXPECT_EQ("bar", AL.getAllArgValues(OPT_B)[1]);
}
TEST(Option, IgnoreCase) {
TestOptTable T(true);
TYPED_TEST(OptTableTest, IgnoreCase) {
TypeParam T(true);
unsigned MAI, MAC;
const char *MyArgs[] = { "-a", "-joo" };
@ -172,8 +198,8 @@ TEST(Option, IgnoreCase) {
EXPECT_TRUE(AL.hasArg(OPT_B));
}
TEST(Option, DoNotIgnoreCase) {
TestOptTable T;
TYPED_TEST(OptTableTest, DoNotIgnoreCase) {
TypeParam T;
unsigned MAI, MAC;
const char *MyArgs[] = { "-a", "-joo" };
@ -182,8 +208,8 @@ TEST(Option, DoNotIgnoreCase) {
EXPECT_FALSE(AL.hasArg(OPT_B));
}
TEST(Option, SlurpEmpty) {
TestOptTable T;
TYPED_TEST(OptTableTest, SlurpEmpty) {
TypeParam T;
unsigned MAI, MAC;
const char *MyArgs[] = { "-A", "-slurp" };
@ -193,8 +219,8 @@ TEST(Option, SlurpEmpty) {
EXPECT_EQ(0U, AL.getAllArgValues(OPT_Slurp).size());
}
TEST(Option, Slurp) {
TestOptTable T;
TYPED_TEST(OptTableTest, Slurp) {
TypeParam T;
unsigned MAI, MAC;
const char *MyArgs[] = { "-A", "-slurp", "-B", "--", "foo" };
@ -209,8 +235,8 @@ TEST(Option, Slurp) {
EXPECT_EQ("foo", AL.getAllArgValues(OPT_Slurp)[2]);
}
TEST(Option, SlurpJoinedEmpty) {
TestOptTable T;
TYPED_TEST(OptTableTest, SlurpJoinedEmpty) {
TypeParam T;
unsigned MAI, MAC;
const char *MyArgs[] = { "-A", "-slurpjoined" };
@ -220,8 +246,8 @@ TEST(Option, SlurpJoinedEmpty) {
EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 0U);
}
TEST(Option, SlurpJoinedOneJoined) {
TestOptTable T;
TYPED_TEST(OptTableTest, SlurpJoinedOneJoined) {
TypeParam T;
unsigned MAI, MAC;
const char *MyArgs[] = { "-A", "-slurpjoinedfoo" };
@ -232,8 +258,8 @@ TEST(Option, SlurpJoinedOneJoined) {
EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined)[0], "foo");
}
TEST(Option, SlurpJoinedAndSeparate) {
TestOptTable T;
TYPED_TEST(OptTableTest, SlurpJoinedAndSeparate) {
TypeParam T;
unsigned MAI, MAC;
const char *MyArgs[] = { "-A", "-slurpjoinedfoo", "bar", "baz" };
@ -246,8 +272,8 @@ TEST(Option, SlurpJoinedAndSeparate) {
EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]);
}
TEST(Option, SlurpJoinedButSeparate) {
TestOptTable T;
TYPED_TEST(OptTableTest, SlurpJoinedButSeparate) {
TypeParam T;
unsigned MAI, MAC;
const char *MyArgs[] = { "-A", "-slurpjoined", "foo", "bar", "baz" };
@ -260,8 +286,8 @@ TEST(Option, SlurpJoinedButSeparate) {
EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]);
}
TEST(Option, FlagAliasToJoined) {
TestOptTable T;
TYPED_TEST(OptTableTest, FlagAliasToJoined) {
TypeParam T;
unsigned MAI, MAC;
// Check that a flag alias provides an empty argument to a joined option.
@ -273,8 +299,8 @@ TEST(Option, FlagAliasToJoined) {
EXPECT_EQ("", AL.getAllArgValues(OPT_B)[0]);
}
TEST(Option, FindNearest) {
TestOptTable T;
TYPED_TEST(OptTableTest, FindNearest) {
TypeParam T;
std::string Nearest;
// Options that are too short should not be considered
@ -324,8 +350,8 @@ TEST(Option, FindNearest) {
EXPECT_EQ(Nearest, "-doopf1");
}
TEST(DISABLED_Option, FindNearestFIXME) {
TestOptTable T;
TYPED_TEST(DISABLED_OptTableTest, FindNearestFIXME) {
TypeParam T;
std::string Nearest;
// FIXME: Options with joined values should not have those values considered
@ -333,11 +359,10 @@ TEST(DISABLED_Option, FindNearestFIXME) {
// succeed.
EXPECT_EQ(1U, T.findNearest("--erbghFoo", Nearest));
EXPECT_EQ(Nearest, "--ermghFoo");
}
TEST(Option, ParseGroupedShortOptions) {
TestOptTable T;
TYPED_TEST(OptTableTest, ParseGroupedShortOptions) {
TypeParam T;
T.setGroupedShortOptions(true);
unsigned MAI, MAC;
@ -366,8 +391,8 @@ TEST(Option, ParseGroupedShortOptions) {
EXPECT_TRUE(AL3.hasArg(OPT_Blorp));
}
TEST(Option, UnknownOptions) {
TestOptTable T;
TYPED_TEST(OptTableTest, UnknownOptions) {
TypeParam T;
unsigned MAI, MAC;
const char *Args[] = {"-u", "--long", "0"};
for (int I = 0; I < 2; ++I) {
@ -380,8 +405,8 @@ TEST(Option, UnknownOptions) {
}
}
TEST(Option, FlagsWithoutValues) {
TestOptTable T;
TYPED_TEST(OptTableTest, FlagsWithoutValues) {
TypeParam T;
T.setGroupedShortOptions(true);
unsigned MAI, MAC;
const char *Args[] = {"-A=1", "-A="};
@ -392,8 +417,8 @@ TEST(Option, FlagsWithoutValues) {
EXPECT_EQ("-A=", Unknown[1]);
}
TEST(Option, UnknownGroupedShortOptions) {
TestOptTable T;
TYPED_TEST(OptTableTest, UnknownGroupedShortOptions) {
TypeParam T;
T.setGroupedShortOptions(true);
unsigned MAI, MAC;
const char *Args[] = {"-AuzK", "-AuzK"};

@ -237,8 +237,14 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
CurPrefix = NewPrefix;
}
// Dump prefixes.
DenseSet<StringRef> PrefixesUnionSet;
for (const auto &Prefix : Prefixes)
PrefixesUnionSet.insert(Prefix.first.begin(), Prefix.first.end());
SmallVector<StringRef> PrefixesUnion(PrefixesUnionSet.begin(),
PrefixesUnionSet.end());
array_pod_sort(PrefixesUnion.begin(), PrefixesUnion.end());
// Dump prefixes.
OS << "/////////\n";
OS << "// Prefixes\n\n";
OS << "#ifdef PREFIX\n";
@ -259,6 +265,20 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
OS << "#undef COMMA\n";
OS << "#endif // PREFIX\n\n";
// Dump prefix unions.
OS << "/////////\n";
OS << "// Prefix Union\n\n";
OS << "#ifdef PREFIX_UNION\n";
OS << "#define COMMA ,\n";
OS << "PREFIX_UNION({\n";
for (const auto &Prefix : PrefixesUnion) {
OS << "llvm::StringLiteral(\"" << Prefix << "\") COMMA ";
}
OS << "llvm::StringLiteral(\"\")})\n";
OS << "#undef COMMA\n";
OS << "#endif // PREFIX_UNION\n\n";
// Dump groups.
OS << "/////////\n";
OS << "// ValuesCode\n\n";
OS << "#ifdef OPTTABLE_VALUES_CODE\n";