|
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 |
|
@@ -277,7 +287,8 @@ static void setPGOOptions(TargetMachine &TM) { |
277 | 287 | TM.setPGOOption(PGOOpt); |
278 | 288 | } |
279 | 289 |
|
280 | | -static int compileModule(char **, LLVMContext &); |
| 290 | +static int compileModule(char **argv, LLVMContext &Context, |
| 291 | + std::string &OutputFilename); |
281 | 292 |
|
282 | 293 | [[noreturn]] static void reportError(Twine Msg, StringRef Filename = "") { |
283 | 294 | SmallString<256> Prefix; |
@@ -356,6 +367,50 @@ static std::unique_ptr<ToolOutputFile> GetOutputStream(const char *TargetName, |
356 | 367 | return FDOut; |
357 | 368 | } |
358 | 369 |
|
| 370 | +static int MaybeEnableStats() { |
| 371 | + if (SaveStats.getNumOccurrences() > 0) { |
| 372 | + if (SaveStats.empty() || SaveStats == "cwd" || SaveStats == "obj") { |
| 373 | + llvm::EnableStatistics(false); |
| 374 | + } else { |
| 375 | + WithColor::error(errs(), "llc") |
| 376 | + << "Invalid --save-stats value: " << SaveStats |
| 377 | + << ", must be empty, 'cwd' or 'obj'\n"; |
| 378 | + return 1; |
| 379 | + } |
| 380 | + } |
| 381 | + return 0; |
| 382 | +} |
| 383 | + |
| 384 | +static int MaybeSaveStats(std::string &&OutputFilename) { |
| 385 | + if (SaveStats.getNumOccurrences() > 0) { |
| 386 | + SmallString<128> StatsFilename; |
| 387 | + if (SaveStats == "obj") { |
| 388 | + StatsFilename = OutputFilename; |
| 389 | + llvm::sys::path::remove_filename(StatsFilename); |
| 390 | + } else { |
| 391 | + assert((SaveStats.empty() || SaveStats == "cwd") && |
| 392 | + "Should have been a valid --save-stats value"); |
| 393 | + } |
| 394 | + |
| 395 | + auto BaseName = llvm::sys::path::filename(OutputFilename); |
| 396 | + llvm::sys::path::append(StatsFilename, BaseName); |
| 397 | + llvm::sys::path::replace_extension(StatsFilename, "stats"); |
| 398 | + |
| 399 | + auto FileFlags = llvm::sys::fs::OF_TextWithCRLF; |
| 400 | + std::error_code EC; |
| 401 | + auto StatsOS = |
| 402 | + std::make_unique<llvm::raw_fd_ostream>(StatsFilename, EC, FileFlags); |
| 403 | + if (EC) { |
| 404 | + WithColor::error(errs(), "llc") |
| 405 | + << "Unable to open statistics file: " << EC.message() << "\n"; |
| 406 | + return 1; |
| 407 | + } else { |
| 408 | + llvm::PrintStatisticsJSON(*StatsOS); |
| 409 | + } |
| 410 | + } |
| 411 | + return 0; |
| 412 | +} |
| 413 | + |
359 | 414 | // main - Entry point for the llc compiler. |
360 | 415 | // |
361 | 416 | int main(int argc, char **argv) { |
@@ -433,18 +488,23 @@ int main(int argc, char **argv) { |
433 | 488 | reportError(std::move(E), RemarksFilename); |
434 | 489 | LLVMRemarkFileHandle RemarksFile = std::move(*RemarksFileOrErr); |
435 | 490 |
|
| 491 | + if (int RetVal = MaybeEnableStats()) |
| 492 | + return RetVal; |
| 493 | + std::string OutputFilename; |
| 494 | + |
436 | 495 | if (InputLanguage != "" && InputLanguage != "ir" && InputLanguage != "mir") |
437 | 496 | reportError("input language must be '', 'IR' or 'MIR'"); |
438 | 497 |
|
439 | 498 | // Compile the module TimeCompilations times to give better compile time |
440 | 499 | // metrics. |
441 | 500 | for (unsigned I = TimeCompilations; I; --I) |
442 | | - if (int RetVal = compileModule(argv, Context)) |
| 501 | + if (int RetVal = compileModule(argv, Context, OutputFilename)) |
443 | 502 | return RetVal; |
444 | 503 |
|
445 | 504 | if (RemarksFile) |
446 | 505 | RemarksFile->keep(); |
447 | | - return 0; |
| 506 | + |
| 507 | + return MaybeSaveStats(std::move(OutputFilename)); |
448 | 508 | } |
449 | 509 |
|
450 | 510 | static bool addPass(PassManagerBase &PM, const char *argv0, StringRef PassName, |
@@ -476,7 +536,8 @@ static bool addPass(PassManagerBase &PM, const char *argv0, StringRef PassName, |
476 | 536 | return false; |
477 | 537 | } |
478 | 538 |
|
479 | | -static int compileModule(char **argv, LLVMContext &Context) { |
| 539 | +static int compileModule(char **argv, LLVMContext &Context, |
| 540 | + std::string &OutputFilename) { |
480 | 541 | // Load the module to be compiled... |
481 | 542 | SMDiagnostic Err; |
482 | 543 | std::unique_ptr<Module> M; |
@@ -660,6 +721,9 @@ static int compileModule(char **argv, LLVMContext &Context) { |
660 | 721 | // Ensure the filename is passed down to CodeViewDebug. |
661 | 722 | Target->Options.ObjectFilenameForDebug = Out->outputFilename(); |
662 | 723 |
|
| 724 | + // Return a copy of the output filename via the output param |
| 725 | + OutputFilename = Out->outputFilename(); |
| 726 | + |
663 | 727 | // Tell target that this tool is not necessarily used with argument ABI |
664 | 728 | // compliance (i.e. narrow integer argument extensions). |
665 | 729 | Target->Options.VerifyArgABICompliance = 0; |
|
0 commit comments