================
@@ -3471,32 +3171,574 @@ static int order_main() {
return 0;
}
-int main(int argc, const char *argv[]) {
- InitLLVM X(argc, argv);
- StringRef ProgName(sys::path::filename(argv[0]));
+static void reportCmdLineError(const Twine &Message) {
+ WithColor::error(errs(), ProgramName) << Message << "\n";
+}
+
+template <typename T>
+static bool parseNumericOption(const opt::Arg *A, T &Value) {
+ if (!A)
+ return true;
+ StringRef V = A->getValue();
+ T Parsed{};
+ if (!llvm::to_integer(V, Parsed, 0)) {
+ if (!std::numeric_limits<T>::is_signed && V == "-1") {
+ Value = std::numeric_limits<T>::max();
+ return true;
+ }
+ reportCmdLineError(Twine("invalid argument '") + V + "' for option '" +
+ A->getSpelling() + "'");
+ return false;
+ }
+ Value = Parsed;
+ return true;
+}
+
+static bool applyLibraryOptions(const opt::InputArgList &Args) {
+ SmallVector<std::string, 16> CLStrings;
+ CLStrings.push_back(ProgramName);
+
+ auto AddFlag = [&](unsigned OptID, StringRef Spelling) {
+ if (Args.hasArg(OptID))
+ CLStrings.push_back(Spelling.str());
+ };
+ auto AddUInt = [&](unsigned OptID, StringRef Spelling) -> bool {
+ if (const opt::Arg *A = Args.getLastArg(OptID)) {
+ uint64_t Value = 0;
+ if (!parseNumericOption(A, Value))
+ return false;
+ CLStrings.push_back((Spelling + Twine("=") + Twine(Value)).str());
+ }
+ return true;
+ };
+ auto AddInt = [&](unsigned OptID, StringRef Spelling) -> bool {
+ if (const opt::Arg *A = Args.getLastArg(OptID)) {
+ int Value = 0;
+ if (!parseNumericOption(A, Value))
+ return false;
+ CLStrings.push_back((Spelling + Twine("=") + Twine(Value)).str());
+ }
+ return true;
+ };
+
+ AddFlag(OPT_profile_isfs, "--profile-isfs");
+ AddFlag(OPT_generate_merged_base_profiles,
"--generate-merged-base-profiles");
+ if (!AddUInt(OPT_profile_symbol_list_cutoff, "--profile-symbol-list-cutoff"))
+ return false;
+ AddFlag(OPT_extbinary_write_vtable_type_prof,
+ "--extbinary-write-vtable-type-prof");
+
+ AddFlag(OPT_profile_summary_contextless, "--profile-summary-contextless");
+ if (!AddInt(OPT_profile_summary_cutoff_hot, "--profile-summary-cutoff-hot"))
+ return false;
+ if (!AddInt(OPT_profile_summary_cutoff_cold,
"--profile-summary-cutoff-cold"))
+ return false;
+ if (!AddUInt(OPT_profile_summary_hot_count, "--profile-summary-hot-count"))
+ return false;
+ if (!AddUInt(OPT_profile_summary_cold_count, "--profile-summary-cold-count"))
+ return false;
+ if (!AddUInt(OPT_profile_summary_huge_working_set_size_threshold,
+ "--profile-summary-huge-working-set-size-threshold"))
+ return false;
+ if (!AddUInt(OPT_profile_summary_large_working_set_size_threshold,
+ "--profile-summary-large-working-set-size-threshold"))
+ return false;
+
+ if (CLStrings.size() == 1)
+ return true;
+
+ SmallVector<char *, 16> CLArgs;
+ for (std::string &S : CLStrings)
+ CLArgs.push_back(S.data());
+
+ return cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data(),
+ /*Overview=*/"", /*Errs=*/nullptr,
+ /*VFS=*/nullptr,
+ /*EnvVar=*/nullptr,
+ /*LongOptionsUseDoubleDash=*/false);
+}
+
+static bool parseFloatOption(const opt::Arg *A, float &Value) {
+ if (!A)
+ return true;
+ StringRef V = A->getValue();
+ double Parsed;
+ if (V.getAsDouble(Parsed)) {
+ reportCmdLineError(Twine("invalid argument '") + V + "' for option '" +
+ A->getSpelling() + "'");
+ return false;
+ }
+ Value = static_cast<float>(Parsed);
+ return true;
+}
+
+static bool parseCutoffValues(const opt::InputArgList &Args,
+ std::vector<uint32_t> &Cutoffs) {
+ Cutoffs.clear();
+ for (const opt::Arg *A : Args.filtered(OPT_detailed_summary_cutoffs)) {
+ SmallVector<StringRef, 4> Parts;
+ StringRef(A->getValue())
+ .split(Parts, ',', /*MaxSplit=*/-1,
+ /*KeepEmpty=*/false);
+ for (StringRef Part : Parts) {
+ uint32_t Parsed;
+ if (!llvm::to_integer(Part, Parsed, 0)) {
+ reportCmdLineError(Twine("invalid argument '") + Part +
+ "' for option '" + A->getSpelling() + "'");
+ return false;
+ }
+ Cutoffs.push_back(Parsed);
+ }
+ }
+ return true;
+}
+
+static bool parseFSDiscriminatorPassArg(const opt::InputArgList &Args) {
+ const opt::Arg *A = Args.getLastArg(OPT_fs_discriminator_pass);
+ if (!A)
+ return true;
+
+ StringRef Value = A->getValue();
+ auto Parsed = StringSwitch<std::optional<FSDiscriminatorPass>>(Value)
+ .Case("Base", FSDiscriminatorPass::Base)
+ .Case("base", FSDiscriminatorPass::Base)
+ .Case("Pass1", FSDiscriminatorPass::Pass1)
+ .Case("pass1", FSDiscriminatorPass::Pass1)
+ .Case("Pass2", FSDiscriminatorPass::Pass2)
+ .Case("pass2", FSDiscriminatorPass::Pass2)
+ .Case("Pass3", FSDiscriminatorPass::Pass3)
+ .Case("pass3", FSDiscriminatorPass::Pass3)
+ .Case("PassLast", FSDiscriminatorPass::PassLast)
+ .Case("pass-last", FSDiscriminatorPass::PassLast)
+ .Case("passlast", FSDiscriminatorPass::PassLast)
+ .Default(std::nullopt);
+ if (!Parsed) {
+ reportCmdLineError(Twine("invalid argument '") + Value + "' for option '" +
+ A->getSpelling() + "'");
+ return false;
+ }
+ FSDiscriminatorPassOption = *Parsed;
+ return true;
+}
+
+static bool validateSubcommandOptions(const opt::InputArgList &Args,
+ StringRef Subcommand) {
+ bool Valid = true;
+ for (const opt::Arg *A : Args) {
+ if (A->getOption().matches(OPT_UNKNOWN) ||
+ A->getOption().matches(OPT_INPUT))
+ continue;
+ // Options without an explicit subcommand are available everywhere.
+ if (A->getOption().matches(OPT_help) ||
A->getOption().matches(OPT_version))
+ continue;
+ if (A->getOption().isRegisteredSC(Subcommand))
+ continue;
+ reportCmdLineError(Twine("unknown command line argument '") +
+ A->getSpelling() + "' for subcommand '" + Subcommand +
+ "'. Try: '" + ProgramName + " " + Subcommand +
+ " --help'");
+ Valid = false;
+ }
+ return Valid;
+}
+
+static bool parseMergeOptions(const opt::InputArgList &Args,
+ ArrayRef<StringRef> Positionals) {
+ OutputFilename = Args.getLastArgValue(OPT_output, "-").str();
+ if (const opt::Arg *A = Args.getLastArg(OPT_sample, OPT_instr))
+ ProfileKind = A->getOption().matches(OPT_sample) ? sample : instr;
+ if (!applyLibraryOptions(Args))
+ return false;
+
+ if (!parseNumericOption(
+ Args.getLastArg(OPT_max_debug_info_correlation_warnings),
+ MaxDbgCorrelationWarnings))
+ return false;
+ ProfiledBinary = Args.getLastArgValue(OPT_profiled_binary).str();
+ DebugInfoFilename = Args.getLastArgValue(OPT_debug_info).str();
+ BinaryFilename = Args.getLastArgValue(OPT_binary_file).str();
+ DebugFileDirectory = Args.getAllArgValues(OPT_debug_file_directory);
+ DebugInfod = Args.hasArg(OPT_debuginfod);
+
+ if (const opt::Arg *A = Args.getLastArg(OPT_correlate)) {
+ StringRef V = A->getValue();
+ auto Parsed = StringSwitch<std::optional<ProfCorrelatorKind>>(V)
+ .Case("", InstrProfCorrelator::NONE)
+ .Case("debug-info", InstrProfCorrelator::DEBUG_INFO)
+ .Case("binary", InstrProfCorrelator::BINARY)
+ .Default(std::nullopt);
+ if (!Parsed) {
+ reportCmdLineError(Twine("invalid argument '") + V + "' for option '" +
+ A->getSpelling() + "'");
+ return false;
+ }
+ BIDFetcherProfileCorrelate = *Parsed;
+ }
+
+ FuncNameFilter = Args.getLastArgValue(OPT_function).str();
+ InputFilenames.clear();
+ InputFilenames.reserve(Positionals.size());
+ for (StringRef Pos : Positionals)
+ InputFilenames.emplace_back(Pos.str());
+ WeightedInputFilenames = Args.getAllArgValues(OPT_weighted_input);
+
+ OutputFormat = PF_Ext_Binary;
+ if (const opt::Arg *Fmt =
+ Args.getLastArg(OPT_binary, OPT_extbinary, OPT_text, OPT_gcc)) {
+ if (Fmt->getOption().matches(OPT_binary))
+ OutputFormat = PF_Binary;
+ else if (Fmt->getOption().matches(OPT_gcc))
+ OutputFormat = PF_GCC;
+ else if (Fmt->getOption().matches(OPT_text))
+ OutputFormat = PF_Text;
+ else
+ OutputFormat = PF_Ext_Binary;
+ }
+
+ InputFilenamesFile = Args.getLastArgValue(OPT_input_files).str();
+ DumpInputFileList = Args.hasArg(OPT_dump_input_file_list);
+ RemappingFile = Args.getLastArgValue(OPT_remapping_file).str();
+ UseMD5 = Args.hasArg(OPT_use_md5);
+ CompressAllSections = Args.hasArg(OPT_compress_all_sections);
+ SampleMergeColdContext = Args.hasArg(OPT_sample_merge_cold_context);
+ SampleTrimColdContext = Args.hasArg(OPT_sample_trim_cold_context);
+ if (!parseNumericOption(
+ Args.getLastArg(OPT_sample_frame_depth_for_cold_context),
+ SampleColdContextFrameDepth))
+ return false;
+ if (!parseNumericOption(Args.getLastArg(OPT_output_size_limit),
+ OutputSizeLimit))
+ return false;
+ GenPartialProfile = Args.hasArg(OPT_gen_partial_profile);
+ SplitLayout = Args.hasArg(OPT_split_layout);
+ SupplInstrWithSample =
+ Args.getLastArgValue(OPT_supplement_instr_with_sample).str();
+ if (!parseFloatOption(Args.getLastArg(OPT_zero_counter_threshold),
+ ZeroCounterThreshold))
+ return false;
+ if (!parseNumericOption(Args.getLastArg(OPT_suppl_min_size_threshold),
+ SupplMinSizeThreshold))
+ return false;
+ if (!parseNumericOption(Args.getLastArg(OPT_instr_prof_cold_threshold),
+ InstrProfColdThreshold))
+ return false;
+ if (!parseNumericOption(
+ Args.getLastArg(OPT_temporal_profile_trace_reservoir_size),
+ TemporalProfTraceReservoirSize))
+ return false;
+ if (!parseNumericOption(
+ Args.getLastArg(OPT_temporal_profile_max_trace_length),
+ TemporalProfMaxTraceLength))
+ return false;
+ FuncNameNegativeFilter = Args.getLastArgValue(OPT_no_function).str();
+
+ StringRef FailureModeValue = Args.getLastArgValue(OPT_failure_mode, "any");
+ auto ParsedFailMode =
+ StringSwitch<std::optional<FailureMode>>(FailureModeValue)
+ .Case("warn", warnOnly)
+ .Case("any", failIfAnyAreInvalid)
+ .Case("all", failIfAllAreInvalid)
+ .Default(std::nullopt);
+ if (!ParsedFailMode) {
+ reportCmdLineError(Twine("invalid argument '") + FailureModeValue +
+ "' for option '--failure-mode'");
+ return false;
+ }
+ FailMode = *ParsedFailMode;
+
+ OutputSparse = Args.hasArg(OPT_sparse);
+ if (!parseNumericOption(Args.getLastArg(OPT_num_threads), NumThreads))
+ return false;
+ ProfileSymbolListFile = Args.getLastArgValue(OPT_prof_sym_list).str();
+
+ if (const opt::Arg *A = Args.getLastArg(OPT_convert_sample_profile_layout)) {
+ StringRef Layout = A->getValue();
+ auto ParsedLayout =
StringSwitch<std::optional<SampleProfileLayout>>(Layout)
+ .Case("nest", SPL_Nest)
+ .Case("flat", SPL_Flat)
+ .Default(std::nullopt);
+ if (!ParsedLayout) {
+ reportCmdLineError(Twine("invalid argument '") + Layout +
+ "' for option '" + A->getSpelling() + "'");
+ return false;
+ }
+ ProfileLayout = *ParsedLayout;
+ }
+
+ DropProfileSymbolList = Args.hasArg(OPT_drop_profile_symbol_list);
+ KeepVTableSymbols = Args.hasArg(OPT_keep_vtable_symbols);
+ DoWritePrevVersion = Args.hasArg(OPT_write_prev_version);
+
+ if (const opt::Arg *A = Args.getLastArg(OPT_memprof_version)) {
+ StringRef Version = A->getValue();
+ auto ParsedVersion =
+ StringSwitch<std::optional<memprof::IndexedVersion>>(Version)
+ .Case("2", memprof::Version2)
+ .Case("3", memprof::Version3)
+ .Case("4", memprof::Version4)
+ .Default(std::nullopt);
+ if (!ParsedVersion) {
+ reportCmdLineError(Twine("invalid argument '") + Version +
+ "' for option '" + A->getSpelling() + "'");
+ return false;
+ }
+ MemProfVersionRequested = *ParsedVersion;
+ }
+
+ MemProfFullSchema = Args.hasArg(OPT_memprof_full_schema);
+ MemprofGenerateRandomHotness = Args.hasArg(OPT_memprof_random_hotness);
+ if (!parseNumericOption(Args.getLastArg(OPT_memprof_random_hotness_seed),
+ MemprofGenerateRandomHotnessSeed))
+ return false;
+
+ if (!parseFSDiscriminatorPassArg(Args))
+ return false;
+
+ return true;
+}
+
+static bool parseShowOptions(const opt::InputArgList &Args,
+ ArrayRef<StringRef> Positionals) {
+ OutputFilename = Args.getLastArgValue(OPT_output, "-").str();
+ DebugInfoFilename = Args.getLastArgValue(OPT_debug_info).str();
+ ProfiledBinary = Args.getLastArgValue(OPT_profiled_binary).str();
+ FuncNameFilter = Args.getLastArgValue(OPT_function).str();
+ if (!Positionals.empty()) {
+ Filename = Positionals.front().str();
+ if (Positionals.size() > 1) {
+ reportCmdLineError("too many positional arguments");
+ return false;
+ }
+ }
+ if (Filename.empty() && DebugInfoFilename.empty()) {
+ reportCmdLineError(
+ "the positional argument '<profdata-file>' is required unless "
+ "'--debug-info' is provided");
+ return false;
+ }
+ if (!Filename.empty() && OutputFilename == Filename) {
+ reportCmdLineError("show: Input file name cannot be the same as the "
+ "output file name!");
+ return false;
+ }
+
+ if (!parseNumericOption(
+ Args.getLastArg(OPT_max_debug_info_correlation_warnings),
+ MaxDbgCorrelationWarnings))
+ return false;
+ if (!applyLibraryOptions(Args))
+ return false;
+
+ ShowCounts = Args.hasArg(OPT_counts);
+ if (const opt::Arg *A = Args.getLastArg(OPT_show_format)) {
+ StringRef Value = A->getValue();
+ auto Parsed = StringSwitch<std::optional<ShowFormat>>(Value)
+ .Case("text", ShowFormat::Text)
+ .Case("json", ShowFormat::Json)
+ .Case("yaml", ShowFormat::Yaml)
+ .Default(std::nullopt);
+ if (!Parsed) {
+ reportCmdLineError(Twine("invalid argument '") + Value +
+ "' for option '" + A->getSpelling() + "'");
+ return false;
+ }
+ SFormat = *Parsed;
+ }
+ TextFormat = Args.hasArg(OPT_text);
+ JsonFormat = Args.hasArg(OPT_json);
+ ShowIndirectCallTargets = Args.hasArg(OPT_ic_targets);
+ ShowVTables = Args.hasArg(OPT_show_vtables);
+ ShowMemOPSizes = Args.hasArg(OPT_memop_sizes);
+ ShowDetailedSummary = Args.hasArg(OPT_detailed_summary);
+ if (!parseCutoffValues(Args, DetailedSummaryCutoffs))
+ return false;
+ ShowHotFuncList = Args.hasArg(OPT_hot_func_list);
+ ShowAllFunctions = Args.hasArg(OPT_all_functions);
+ ShowCS = Args.hasArg(OPT_showcs);
+ if (!parseNumericOption(Args.getLastArg(OPT_topn), TopNFunctions))
+ return false;
+ if (!parseNumericOption(Args.getLastArg(OPT_value_cutoff), ShowValueCutoff))
+ return false;
+ OnlyListBelow = Args.hasArg(OPT_list_below_cutoff);
+ ShowProfileSymbolList = Args.hasArg(OPT_show_prof_sym_list);
+ ShowSectionInfoOnly = Args.hasArg(OPT_show_sec_info_only);
+ ShowBinaryIds = Args.hasArg(OPT_binary_ids);
+ ShowTemporalProfTraces = Args.hasArg(OPT_temporal_profile_traces);
+ ShowCovered = Args.hasArg(OPT_covered);
+ ShowProfileVersion = Args.hasArg(OPT_profile_version);
+
+ if (const opt::Arg *A = Args.getLastArg(OPT_memory, OPT_sample, OPT_instr)) {
+ if (A->getOption().matches(OPT_memory))
+ ShowProfileKind = memory;
+ else if (A->getOption().matches(OPT_sample))
+ ShowProfileKind = sample;
+ else
+ ShowProfileKind = instr;
+ }
+
+ if (!parseFSDiscriminatorPassArg(Args))
+ return false;
+
+ return true;
+}
+
+static bool parseOverlapOptions(const opt::InputArgList &Args,
+ ArrayRef<StringRef> Positionals) {
+ OutputFilename = Args.getLastArgValue(OPT_output, "-").str();
+ if (Positionals.size() != 2) {
+ reportCmdLineError("overlap requires two positional profile filenames");
+ return false;
+ }
+ BaseFilename = Positionals[0].str();
+ TestFilename = Positionals[1].str();
+
+ if (const opt::Arg *A = Args.getLastArg(OPT_sample, OPT_instr))
+ ProfileKind = A->getOption().matches(OPT_sample) ? sample : instr;
+
+ FuncNameFilter = Args.getLastArgValue(OPT_function).str();
+ if (!parseNumericOption(Args.getLastArg(OPT_similarity_cutoff),
+ SimilarityCutoff))
+ return false;
+ IsCS = Args.hasArg(OPT_cs);
+ if (!parseNumericOption(Args.getLastArg(OPT_value_cutoff),
+ OverlapValueCutoff))
+ return false;
+
+ if (!parseFSDiscriminatorPassArg(Args))
+ return false;
+
+ return true;
+}
- if (argc < 2) {
- errs()
- << ProgName
- << ": No subcommand specified! Run llvm-profdata --help for usage.\n";
+static bool parseOrderOptions(const opt::InputArgList &Args,
+ ArrayRef<StringRef> Positionals) {
+ OutputFilename = Args.getLastArgValue(OPT_output, "-").str();
+ if (!Positionals.empty()) {
+ Filename = Positionals.front().str();
+ if (Positionals.size() > 1) {
+ reportCmdLineError("too many positional arguments");
+ return false;
+ }
+ }
+ if (!parseNumericOption(Args.getLastArg(OPT_num_test_traces), NumTestTraces))
+ return false;
+ return true;
+}
+
+int llvm_profdata_main(int argc, char **argv, const llvm::ToolContext &) {
+ BumpPtrAllocator Alloc;
+ StringSaver Saver(Alloc);
+
+ ProgramName = sys::path::stem(argv[0]).str();
+
+ ProfdataOptTable Tbl;
+
+ if (argc == 1) {
+ errs() << ProgramName << ": No subcommand specified! Run " << ProgramName
+ << " --help for usage.\n";
return 1;
}
- cl::ParseCommandLineOptions(argc, argv, "LLVM profile data\n");
+ bool HadParseError = false;
+ opt::InputArgList Args =
+ Tbl.parseArgs(argc - 1, argv + 1, OPT_UNKNOWN, Saver, [&](StringRef Msg)
{
+ WithColor::error(errs(), ProgramName) << Msg << "\n";
+ HadParseError = true;
+ });
+ if (HadParseError)
+ return 1;
+
+ bool HadSubcommandError = false;
+ SmallVector<StringRef, 4> OtherPositionals;
+ auto HandleMultipleSubcommands = [&](ArrayRef<StringRef> SubCommands) {
+ HadSubcommandError = true;
+ WithColor::error(errs(), ProgramName) << "multiple subcommands specified:";
+ for (StringRef SC : SubCommands)
+ errs() << " '" << SC << "'";
+ errs() << "\n";
+ };
+ auto HandleOtherPositionals = [&](ArrayRef<StringRef> Positionals) {
+ OtherPositionals.append(Positionals.begin(), Positionals.end());
+ };
- if (ShowSubcommand)
- return show_main(ProgName);
+ auto IsKnownSubcommand = [&](StringRef Name) {
+ return llvm::any_of(
+ Tbl.getSubCommands(),
+ [&](const opt::OptTable::SubCommand &SC) { return Name == SC.Name; });
+ };
- if (OrderSubcommand)
- return order_main();
+ StringRef RawFirstArg = argc > 1 ? StringRef(argv[1]) : StringRef();
+ StringRef RawSubcommand =
+ IsKnownSubcommand(RawFirstArg) ? RawFirstArg : StringRef();
- if (OverlapSubcommand)
- return overlap_main();
+ StringRef Subcommand = Args.getSubCommand(
+ Tbl.getSubCommands(), HandleMultipleSubcommands, HandleOtherPositionals);
+ if (HadSubcommandError)
+ return 1;
- if (MergeSubcommand)
- return merge_main(ProgName);
+ if (Subcommand.empty() && !OtherPositionals.empty() &&
+ IsKnownSubcommand(OtherPositionals.front())) {
+ Subcommand = OtherPositionals.front();
+ OtherPositionals.erase(OtherPositionals.begin());
+ }
+ if (Subcommand.empty() && !RawSubcommand.empty()) {
+ Subcommand = RawSubcommand;
+ auto It = llvm::find(OtherPositionals, Subcommand);
+ if (It != OtherPositionals.end())
+ OtherPositionals.erase(It);
+ }
+
+ auto HasRawFlag = [&](StringRef Flag) {
+ return llvm::is_contained(OtherPositionals, Flag) || RawFirstArg == Flag;
+ };
+
+ if (Args.hasArg(OPT_help) || HasRawFlag("--help")) {
----------------
dzbarsky wrote:
even as top-level options I was seeing these not resolving if no command was
selected, so needed this workaround. Maybe I missed something?
https://github.com/llvm/llvm-project/pull/177868
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits