|
15 | 15 | #include "NewPMDriver.h" |
16 | 16 | #include "llvm/ADT/STLExtras.h" |
17 | 17 | #include "llvm/ADT/ScopeExit.h" |
| 18 | +#include "llvm/ADT/Statistic.h" |
18 | 19 | #include "llvm/Analysis/TargetLibraryInfo.h" |
19 | 20 | #include "llvm/CodeGen/CommandFlags.h" |
20 | 21 | #include "llvm/CodeGen/LinkAllAsmWriterComponents.h" |
|
45 | 46 | #include "llvm/Support/FormattedStream.h" |
46 | 47 | #include "llvm/Support/InitLLVM.h" |
47 | 48 | #include "llvm/Support/PGOOptions.h" |
| 49 | +#include "llvm/Support/Path.h" |
48 | 50 | #include "llvm/Support/PluginLoader.h" |
49 | 51 | #include "llvm/Support/SourceMgr.h" |
50 | 52 | #include "llvm/Support/TargetSelect.h" |
|
57 | 59 | #include "llvm/TargetParser/SubtargetFeature.h" |
58 | 60 | #include "llvm/TargetParser/Triple.h" |
59 | 61 | #include "llvm/Transforms/Utils/Cloning.h" |
| 62 | +#include <cassert> |
60 | 63 | #include <memory> |
61 | 64 | #include <optional> |
62 | 65 | using namespace llvm; |
@@ -203,6 +206,13 @@ static cl::opt<std::string> RemarksFormat( |
203 | 206 | cl::desc("The format used for serializing remarks (default: YAML)"), |
204 | 207 | cl::value_desc("format"), cl::init("yaml")); |
205 | 208 |
|
| 209 | +static cl::opt<std::string> SaveStats( |
| 210 | + "save-stats", |
| 211 | + cl::desc("Save LLVM statistics to a file in the current directory" |
| 212 | + "(`-save-stats`/`-save-stats=cwd`) or the directory of the output" |
| 213 | + "file (`-save-stats=obj`). (default: cwd)"), |
| 214 | + cl::init(""), cl::ValueOptional); |
| 215 | + |
206 | 216 | static cl::opt<bool> EnableNewPassManager( |
207 | 217 | "enable-new-pm", cl::desc("Enable the new pass manager"), cl::init(false)); |
208 | 218 |
|
@@ -276,7 +286,8 @@ static void setPGOOptions(TargetMachine &TM) { |
276 | 286 | TM.setPGOOption(PGOOpt); |
277 | 287 | } |
278 | 288 |
|
279 | | -static int compileModule(char **, LLVMContext &); |
| 289 | +static int compileModule(char **argv, LLVMContext &Context, |
| 290 | + std::string &OutputFilename); |
280 | 291 |
|
281 | 292 | [[noreturn]] static void reportError(Twine Msg, StringRef Filename = "") { |
282 | 293 | SmallString<256> Prefix; |
@@ -355,6 +366,50 @@ static std::unique_ptr<ToolOutputFile> GetOutputStream(const char *TargetName, |
355 | 366 | return FDOut; |
356 | 367 | } |
357 | 368 |
|
| 369 | +static int MaybeEnableStats() { |
| 370 | + if (SaveStats.getNumOccurrences() > 0) { |
| 371 | + if (SaveStats.empty() || SaveStats == "cwd" || SaveStats == "obj") { |
| 372 | + llvm::EnableStatistics(false); |
| 373 | + } else { |
| 374 | + WithColor::error(errs(), "llc") |
| 375 | + << "Invalid --save-stats value: " << SaveStats |
| 376 | + << ", must be empty, 'cwd' or 'obj'\n"; |
| 377 | + return 1; |
| 378 | + } |
| 379 | + } |
| 380 | + return 0; |
| 381 | +} |
| 382 | + |
| 383 | +static int MaybeSaveStats(std::string &&OutputFilename) { |
| 384 | + if (SaveStats.getNumOccurrences() > 0) { |
| 385 | + SmallString<128> StatsFilename; |
| 386 | + if (SaveStats == "obj") { |
| 387 | + StatsFilename = OutputFilename; |
| 388 | + llvm::sys::path::remove_filename(StatsFilename); |
| 389 | + } else { |
| 390 | + assert((SaveStats.empty() || SaveStats == "cwd") && |
| 391 | + "Should have been a valid --save-stats value"); |
| 392 | + } |
| 393 | + |
| 394 | + auto BaseName = llvm::sys::path::filename(OutputFilename); |
| 395 | + llvm::sys::path::append(StatsFilename, BaseName); |
| 396 | + llvm::sys::path::replace_extension(StatsFilename, "stats"); |
| 397 | + |
| 398 | + auto FileFlags = llvm::sys::fs::OF_TextWithCRLF; |
| 399 | + std::error_code EC; |
| 400 | + auto StatsOS = |
| 401 | + std::make_unique<llvm::raw_fd_ostream>(StatsFilename, EC, FileFlags); |
| 402 | + if (EC) { |
| 403 | + WithColor::error(errs(), "llc") |
| 404 | + << "Unable to open statistics file: " << EC.message() << "\n"; |
| 405 | + return 1; |
| 406 | + } else { |
| 407 | + llvm::PrintStatisticsJSON(*StatsOS); |
| 408 | + } |
| 409 | + } |
| 410 | + return 0; |
| 411 | +} |
| 412 | + |
358 | 413 | // main - Entry point for the llc compiler. |
359 | 414 | // |
360 | 415 | int main(int argc, char **argv) { |
@@ -432,18 +487,23 @@ int main(int argc, char **argv) { |
432 | 487 | reportError(std::move(E), RemarksFilename); |
433 | 488 | LLVMRemarkFileHandle RemarksFile = std::move(*RemarksFileOrErr); |
434 | 489 |
|
| 490 | + if (int RetVal = MaybeEnableStats()) |
| 491 | + return RetVal; |
| 492 | + std::string OutputFilename; |
| 493 | + |
435 | 494 | if (InputLanguage != "" && InputLanguage != "ir" && InputLanguage != "mir") |
436 | 495 | reportError("input language must be '', 'IR' or 'MIR'"); |
437 | 496 |
|
438 | 497 | // Compile the module TimeCompilations times to give better compile time |
439 | 498 | // metrics. |
440 | 499 | for (unsigned I = TimeCompilations; I; --I) |
441 | | - if (int RetVal = compileModule(argv, Context)) |
| 500 | + if (int RetVal = compileModule(argv, Context, OutputFilename)) |
442 | 501 | return RetVal; |
443 | 502 |
|
444 | 503 | if (RemarksFile) |
445 | 504 | RemarksFile->keep(); |
446 | | - return 0; |
| 505 | + |
| 506 | + return MaybeSaveStats(std::move(OutputFilename)); |
447 | 507 | } |
448 | 508 |
|
449 | 509 | static bool addPass(PassManagerBase &PM, const char *argv0, StringRef PassName, |
@@ -475,7 +535,8 @@ static bool addPass(PassManagerBase &PM, const char *argv0, StringRef PassName, |
475 | 535 | return false; |
476 | 536 | } |
477 | 537 |
|
478 | | -static int compileModule(char **argv, LLVMContext &Context) { |
| 538 | +static int compileModule(char **argv, LLVMContext &Context, |
| 539 | + std::string &OutputFilename) { |
479 | 540 | // Load the module to be compiled... |
480 | 541 | SMDiagnostic Err; |
481 | 542 | std::unique_ptr<Module> M; |
@@ -659,6 +720,9 @@ static int compileModule(char **argv, LLVMContext &Context) { |
659 | 720 | // Ensure the filename is passed down to CodeViewDebug. |
660 | 721 | Target->Options.ObjectFilenameForDebug = Out->outputFilename(); |
661 | 722 |
|
| 723 | + // Return a copy of the output filename via the output param |
| 724 | + OutputFilename = Out->outputFilename(); |
| 725 | + |
662 | 726 | // Tell target that this tool is not necessarily used with argument ABI |
663 | 727 | // compliance (i.e. narrow integer argument extensions). |
664 | 728 | Target->Options.VerifyArgABICompliance = 0; |
|
0 commit comments