diff --git a/llvm/docs/CommandGuide/llvm-size.rst b/llvm/docs/CommandGuide/llvm-size.rst --- a/llvm/docs/CommandGuide/llvm-size.rst +++ b/llvm/docs/CommandGuide/llvm-size.rst @@ -125,10 +125,6 @@ Display a summary of command line options. -.. option:: --help-list - - Display an uncategorized summary of command line options. - .. option:: -m Equivalent to :option:`--format` with a value of ``darwin``. diff --git a/llvm/test/tools/llvm-size/help.test b/llvm/test/tools/llvm-size/help.test --- a/llvm/test/tools/llvm-size/help.test +++ b/llvm/test/tools/llvm-size/help.test @@ -1,15 +1,10 @@ ## Show that help text is printed correctly when requested. -RUN: llvm-size -h | FileCheck %s --check-prefixes=CHECK,CATEG -RUN: llvm-size --help | FileCheck %s --check-prefixes=CHECK,CATEG -RUN: llvm-size --help-list \ -RUN: | FileCheck %s --check-prefixes=CHECK,LIST +RUN: llvm-size -h | FileCheck %s +RUN: llvm-size --help | FileCheck %s -CHECK: OVERVIEW: llvm object size dumper -CHECK: USAGE: llvm-size{{(.exe)?}} [options] {{$}} +CHECK: OVERVIEW: LLVM object size dumper +CHECK: USAGE: {{.*}}llvm-size{{(.exe)?}} [options] {{$}} CHECK: OPTIONS: -CATEG: Generic Options: -LIST-NOT: Generic Options: -CATEG: llvm-size Options: -LIST-NOT: llvm-size Options: +CHECK: OPTIONS (Mach-O specific): CHECK: @FILE diff --git a/llvm/test/tools/llvm-size/radix.test b/llvm/test/tools/llvm-size/radix.test --- a/llvm/test/tools/llvm-size/radix.test +++ b/llvm/test/tools/llvm-size/radix.test @@ -121,7 +121,7 @@ # RUN: not llvm-size %t1.o --radix=bad 2>&1 \ # RUN: | FileCheck %s --check-prefix=BAD-VAL -DNUM=bad -# BAD-VAL: {{.*}}llvm-size{{.*}}: for the --radix option: Cannot find option named '[[NUM]]'! +# BAD-VAL: {{.*}}llvm-size{{.*}}: error: --radix value should be one of: 8, 10, 16 --- !ELF FileHeader: diff --git a/llvm/test/tools/llvm-size/unknown-format.test b/llvm/test/tools/llvm-size/unknown-format.test --- a/llvm/test/tools/llvm-size/unknown-format.test +++ b/llvm/test/tools/llvm-size/unknown-format.test @@ -1,4 +1,4 @@ ## Show that the an error is emitted if an unknown value is passed to --format. # RUN: not llvm-size --format=unknown 2>&1 | FileCheck %s -# CHECK: {{.*}}llvm-size{{.*}}: for the --format option: Cannot find option named 'unknown'! +# CHECK: {{.*}}llvm-size{{.*}}: error: --format value should be one of: 'berkeley', 'darwin', 'sysv' diff --git a/llvm/tools/llvm-size/CMakeLists.txt b/llvm/tools/llvm-size/CMakeLists.txt --- a/llvm/tools/llvm-size/CMakeLists.txt +++ b/llvm/tools/llvm-size/CMakeLists.txt @@ -1,10 +1,17 @@ set(LLVM_LINK_COMPONENTS Object + Option Support ) +set(LLVM_TARGET_DEFINITIONS Opts.td) +tablegen(LLVM Opts.inc -gen-opt-parser-defs) +add_public_tablegen_target(SizeOptsTableGen) + add_llvm_tool(llvm-size llvm-size.cpp + DEPENDS + SizeOptsTableGen ) if(LLVM_INSTALL_BINUTILS_SYMLINKS) diff --git a/llvm/tools/llvm-size/Opts.td b/llvm/tools/llvm-size/Opts.td new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-size/Opts.td @@ -0,0 +1,32 @@ +include "llvm/Option/OptParser.td" + +class F : Flag<["-"], letter>, HelpText; +class FF : Flag<["--"], name>, HelpText; + +multiclass Eq { + def NAME #_EQ : Joined<["--"], name #"=">, + HelpText; + def : Separate<["--"], name>, Alias(NAME #_EQ)>; +} + +def common : FF<"common", "Print common symbols in the ELF file. When using Berkeley format, this is added to bss">; +defm format : Eq<"format", "Specify output format">; +def help : FF<"help", "Display this help">; +defm radix : Eq<"radix", "Print size in radix">; +def totals : FF<"totals", "Print totals of all objects - Berkeley format only">; +def version : FF<"version", "Display the version">; + +// Mach-O specific options. +def grp_mach_o : OptionGroup<"kind">, HelpText<"OPTIONS (Mach-O specific)">; +def arch_EQ : Joined<["--"], "arch=">, HelpText<"architecture(s) from a Mach-O file to dump">, Group; +def : Separate<["--", "-"], "arch">, Alias; +def l : F<"l", "When format is darwin, use long format to include addresses and offsets">, Group; + +def : F<"A", "Alias for --format">, Alias, AliasArgs<["sysv"]>; +def : F<"B", "Alias for --format">, Alias, AliasArgs<["berkeley"]>; +def : F<"d", "Alias for --radix=10">, Alias, AliasArgs<["10"]>; +def : F<"h", "Alias for --help">, Alias; +def : F<"m", "Alias for --format">, Alias, AliasArgs<["darwin"]>; +def : F<"o", "Alias for --radix=8">, Alias, AliasArgs<["8"]>; +def : F<"t", "Alias for --totals">, Alias; +def : F<"x", "Alias for --radix=16">, Alias, AliasArgs<["16"]>; diff --git a/llvm/tools/llvm-size/llvm-size.cpp b/llvm/tools/llvm-size/llvm-size.cpp --- a/llvm/tools/llvm-size/llvm-size.cpp +++ b/llvm/tools/llvm-size/llvm-size.cpp @@ -18,6 +18,9 @@ #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -33,23 +36,56 @@ using namespace llvm; using namespace object; -cl::OptionCategory SizeCat("llvm-size Options"); +namespace { +using namespace llvm::opt; // for HelpHidden in Opts.inc +enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + OPT_##ID, +#include "Opts.inc" +#undef OPTION +}; + +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "Opts.inc" +#undef PREFIX + +const opt::OptTable::Info InfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + { \ + PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, VALUES}, +#include "Opts.inc" +#undef OPTION +}; + +class SizeOptTable : public opt::OptTable { +public: + SizeOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); } +}; enum OutputFormatTy { berkeley, sysv, darwin }; -static cl::opt - OutputFormat("format", cl::desc("Specify output format"), - cl::values(clEnumVal(sysv, "System V format"), - clEnumVal(berkeley, "Berkeley format"), - clEnumVal(darwin, "Darwin -m format")), - cl::init(berkeley), cl::cat(SizeCat)); - -static cl::opt - OutputFormatShort(cl::desc("Specify output format"), - cl::values(clEnumValN(sysv, "A", "System V format"), - clEnumValN(berkeley, "B", "Berkeley format"), - clEnumValN(darwin, "m", "Darwin -m format")), - cl::init(berkeley), cl::cat(SizeCat)); +enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 }; +} // namespace + +static bool ArchAll = false; +static std::vector ArchFlags; +static bool ELFCommons; +static OutputFormatTy OutputFormat; +static bool DarwinLongFormat; +static RadixTy Radix; +static bool TotalSizes; + +static std::vector InputFilenames; + +static std::string ToolName; +// States +static bool HadError = false; static bool BerkeleyHeaderPrinted = false; static bool MoreThanOneFile = false; static uint64_t TotalObjectText = 0; @@ -57,59 +93,13 @@ static uint64_t TotalObjectBss = 0; static uint64_t TotalObjectTotal = 0; -cl::opt - DarwinLongFormat("l", - cl::desc("When format is darwin, use long format " - "to include addresses and offsets."), - cl::cat(SizeCat)); - -cl::opt - ELFCommons("common", - cl::desc("Print common symbols in the ELF file. When using " - "Berkeley format, this is added to bss."), - cl::init(false), cl::cat(SizeCat)); - -static cl::list - ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"), - cl::ZeroOrMore, cl::cat(SizeCat)); -static bool ArchAll = false; - -enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 }; -static cl::opt Radix( - "radix", cl::desc("Print size in radix"), cl::init(decimal), - cl::values(clEnumValN(octal, "8", "Print size in octal"), - clEnumValN(decimal, "10", "Print size in decimal"), - clEnumValN(hexadecimal, "16", "Print size in hexadecimal")), - cl::cat(SizeCat)); - -static cl::opt RadixShort( - cl::desc("Print size in radix:"), - cl::values(clEnumValN(octal, "o", "Print size in octal"), - clEnumValN(decimal, "d", "Print size in decimal"), - clEnumValN(hexadecimal, "x", "Print size in hexadecimal")), - cl::init(decimal), cl::cat(SizeCat)); - -static cl::opt - TotalSizes("totals", - cl::desc("Print totals of all objects - Berkeley format only"), - cl::init(false), cl::cat(SizeCat)); - -static cl::alias TotalSizesShort("t", cl::desc("Short for --totals"), - cl::aliasopt(TotalSizes)); - -static cl::list - InputFilenames(cl::Positional, cl::desc(""), cl::ZeroOrMore); - -static cl::extrahelp - HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); - -static bool HadError = false; - -static std::string ToolName; - -static void error(const Twine &Message, StringRef File) { +static void error(const Twine &Message, StringRef File = "") { HadError = true; - WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n"; + if (File.empty()) + WithColor::error(errs(), ToolName) << Message << '\n'; + else + WithColor::error(errs(), ToolName) + << "'" << File << "': " << Message << '\n'; } // This version of error() prints the archive name and member name, for example: @@ -874,27 +864,66 @@ int main(int argc, char **argv) { InitLLVM X(argc, argv); - cl::HideUnrelatedOptions(SizeCat); - cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n"); - + BumpPtrAllocator A; + StringSaver Saver(A); + SizeOptTable Tbl; ToolName = argv[0]; - if (OutputFormatShort.getNumOccurrences()) - OutputFormat = static_cast(OutputFormatShort); - if (RadixShort.getNumOccurrences()) - Radix = RadixShort.getValue(); - - for (StringRef Arch : ArchFlags) { - if (Arch == "all") { - ArchAll = true; - } else { - if (!MachOObjectFile::isValidArch(Arch)) { + opt::InputArgList Args = Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, + [&](StringRef Msg) { error(Msg); }); + if (Args.hasArg(OPT_help)) { + Tbl.printHelp( + outs(), + (Twine(ToolName) + " [options] ").str().c_str(), + "LLVM object size dumper"); + // TODO Replace this with OptTable API once it adds extrahelp support. + outs() << "\nPass @FILE as argument to read options from FILE.\n"; + return 0; + } + if (Args.hasArg(OPT_version)) { + outs() << ToolName << '\n'; + cl::PrintVersionMessage(); + return 0; + } + + ELFCommons = Args.hasArg(OPT_common); + DarwinLongFormat = Args.hasArg(OPT_l); + TotalSizes = Args.hasArg(OPT_totals); + StringRef V = Args.getLastArgValue(OPT_format_EQ, "berkeley"); + if (V == "berkeley") + OutputFormat = berkeley; + else if (V == "darwin") + OutputFormat = darwin; + else if (V == "sysv") + OutputFormat = sysv; + else + error("--format value should be one of: 'berkeley', 'darwin', 'sysv'"); + V = Args.getLastArgValue(OPT_radix_EQ, "10"); + if (V == "8") + Radix = RadixTy::octal; + else if (V == "10") + Radix = RadixTy::decimal; + else if (V == "16") + Radix = RadixTy::hexadecimal; + else + error("--radix value should be one of: 8, 10, 16 "); + + for (const auto *A : Args.filtered(OPT_arch_EQ)) { + SmallVector Values; + llvm::SplitString(A->getValue(), Values, ","); + for (StringRef V : Values) { + if (V == "all") + ArchAll = true; + else if (MachOObjectFile::isValidArch(V)) + ArchFlags.push_back(V); + else { outs() << ToolName << ": for the -arch option: Unknown architecture " - << "named '" << Arch << "'"; + << "named '" << V << "'"; return 1; } } } + InputFilenames = Args.getAllArgValues(OPT_INPUT); if (InputFilenames.empty()) InputFilenames.push_back("a.out"); diff --git a/llvm/utils/gn/secondary/llvm/tools/llvm-size/BUILD.gn b/llvm/utils/gn/secondary/llvm/tools/llvm-size/BUILD.gn --- a/llvm/utils/gn/secondary/llvm/tools/llvm-size/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/tools/llvm-size/BUILD.gn @@ -1,6 +1,12 @@ import("//llvm/tools/binutils_symlinks.gni") +import("//llvm/utils/TableGen/tablegen.gni") import("//llvm/utils/gn/build/symlink_or_copy.gni") +tablegen("Opts") { + visibility = [ ":llvm-size" ] + args = [ "-gen-opt-parser-defs" ] +} + if (llvm_install_binutils_symlinks) { symlink_or_copy("size") { deps = [ ":llvm-size" ] @@ -19,7 +25,9 @@ executable("llvm-size") { deps = [ + ":Opts", "//llvm/lib/Object", + "//llvm/lib/Option", "//llvm/lib/Support", ] sources = [ "llvm-size.cpp" ] diff --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel --- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel @@ -3448,6 +3448,18 @@ ], ) +gentbl( + name = "SizeOptsTableGen", + strip_include_prefix = "tools/llvm-size", + tbl_outs = [( + "-gen-opt-parser-defs", + "tools/llvm-size/Opts.inc", + )], + tblgen = ":llvm-tblgen", + td_file = "tools/llvm-size/Opts.td", + td_srcs = ["include/llvm/Option/OptParser.td"], +) + cc_binary( name = "llvm-size", srcs = glob([ @@ -3458,6 +3470,8 @@ stamp = 0, deps = [ ":Object", + ":Option", + ":SizeOptsTableGen", ":Support", ], )