|
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; |
@@ -208,6 +211,20 @@ static cl::opt<std::string> RemarksFormat( |
208 | 211 | cl::desc("The format used for serializing remarks (default: YAML)"), |
209 | 212 | cl::value_desc("format"), cl::init("yaml")); |
210 | 213 |
|
| 214 | +enum SaveStatsMode { None, Cwd, Obj }; |
| 215 | + |
| 216 | +static cl::opt<SaveStatsMode> SaveStats( |
| 217 | + "save-stats", |
| 218 | + cl::desc("Save LLVM statistics to a file in the current directory" |
| 219 | + "(`-save-stats`/`-save-stats=cwd`) or the directory of the output" |
| 220 | + "file (`-save-stats=obj`). (default: cwd)"), |
| 221 | + cl::values(clEnumValN(SaveStatsMode::Cwd, "cwd", |
| 222 | + "Save to the current working directory"), |
| 223 | + clEnumValN(SaveStatsMode::Cwd, "", ""), |
| 224 | + clEnumValN(SaveStatsMode::Obj, "obj", |
| 225 | + "Save to the output file directory")), |
| 226 | + cl::init(SaveStatsMode::None), cl::ValueOptional); |
| 227 | + |
211 | 228 | static cl::opt<bool> EnableNewPassManager( |
212 | 229 | "enable-new-pm", cl::desc("Enable the new pass manager"), cl::init(false)); |
213 | 230 |
|
@@ -281,7 +298,8 @@ static void setPGOOptions(TargetMachine &TM) { |
281 | 298 | TM.setPGOOption(PGOOpt); |
282 | 299 | } |
283 | 300 |
|
284 | | -static int compileModule(char **, LLVMContext &); |
| 301 | +static int compileModule(char **argv, LLVMContext &Context, |
| 302 | + std::string &OutputFilename); |
285 | 303 |
|
286 | 304 | [[noreturn]] static void reportError(Twine Msg, StringRef Filename = "") { |
287 | 305 | SmallString<256> Prefix; |
@@ -360,6 +378,45 @@ static std::unique_ptr<ToolOutputFile> GetOutputStream(const char *TargetName, |
360 | 378 | return FDOut; |
361 | 379 | } |
362 | 380 |
|
| 381 | +static int MaybeEnableStats() { |
| 382 | + if (SaveStats == SaveStatsMode::None) |
| 383 | + return 0; |
| 384 | + |
| 385 | + llvm::EnableStatistics(false); |
| 386 | + return 0; |
| 387 | +} |
| 388 | + |
| 389 | +static int MaybeSaveStats(std::string &&OutputFilename) { |
| 390 | + if (SaveStats == SaveStatsMode::None) |
| 391 | + return 0; |
| 392 | + |
| 393 | + SmallString<128> StatsFilename; |
| 394 | + if (SaveStats == SaveStatsMode::Obj) { |
| 395 | + StatsFilename = OutputFilename; |
| 396 | + llvm::sys::path::remove_filename(StatsFilename); |
| 397 | + } else { |
| 398 | + assert(SaveStats == SaveStatsMode::Cwd && |
| 399 | + "Should have been a valid --save-stats value"); |
| 400 | + } |
| 401 | + |
| 402 | + auto BaseName = llvm::sys::path::filename(OutputFilename); |
| 403 | + llvm::sys::path::append(StatsFilename, BaseName); |
| 404 | + llvm::sys::path::replace_extension(StatsFilename, "stats"); |
| 405 | + |
| 406 | + auto FileFlags = llvm::sys::fs::OF_TextWithCRLF; |
| 407 | + std::error_code EC; |
| 408 | + auto StatsOS = |
| 409 | + std::make_unique<llvm::raw_fd_ostream>(StatsFilename, EC, FileFlags); |
| 410 | + if (EC) { |
| 411 | + WithColor::error(errs(), "llc") |
| 412 | + << "Unable to open statistics file: " << EC.message() << "\n"; |
| 413 | + return 1; |
| 414 | + } |
| 415 | + |
| 416 | + llvm::PrintStatisticsJSON(*StatsOS); |
| 417 | + return 0; |
| 418 | +} |
| 419 | + |
363 | 420 | // main - Entry point for the llc compiler. |
364 | 421 | // |
365 | 422 | int main(int argc, char **argv) { |
@@ -437,18 +494,23 @@ int main(int argc, char **argv) { |
437 | 494 | reportError(std::move(E), RemarksFilename); |
438 | 495 | LLVMRemarkFileHandle RemarksFile = std::move(*RemarksFileOrErr); |
439 | 496 |
|
| 497 | + if (int RetVal = MaybeEnableStats()) |
| 498 | + return RetVal; |
| 499 | + std::string OutputFilename; |
| 500 | + |
440 | 501 | if (InputLanguage != "" && InputLanguage != "ir" && InputLanguage != "mir") |
441 | 502 | reportError("input language must be '', 'IR' or 'MIR'"); |
442 | 503 |
|
443 | 504 | // Compile the module TimeCompilations times to give better compile time |
444 | 505 | // metrics. |
445 | 506 | for (unsigned I = TimeCompilations; I; --I) |
446 | | - if (int RetVal = compileModule(argv, Context)) |
| 507 | + if (int RetVal = compileModule(argv, Context, OutputFilename)) |
447 | 508 | return RetVal; |
448 | 509 |
|
449 | 510 | if (RemarksFile) |
450 | 511 | RemarksFile->keep(); |
451 | | - return 0; |
| 512 | + |
| 513 | + return MaybeSaveStats(std::move(OutputFilename)); |
452 | 514 | } |
453 | 515 |
|
454 | 516 | static bool addPass(PassManagerBase &PM, const char *argv0, StringRef PassName, |
@@ -480,7 +542,8 @@ static bool addPass(PassManagerBase &PM, const char *argv0, StringRef PassName, |
480 | 542 | return false; |
481 | 543 | } |
482 | 544 |
|
483 | | -static int compileModule(char **argv, LLVMContext &Context) { |
| 545 | +static int compileModule(char **argv, LLVMContext &Context, |
| 546 | + std::string &OutputFilename) { |
484 | 547 | // Load the module to be compiled... |
485 | 548 | SMDiagnostic Err; |
486 | 549 | std::unique_ptr<Module> M; |
@@ -664,6 +727,9 @@ static int compileModule(char **argv, LLVMContext &Context) { |
664 | 727 | // Ensure the filename is passed down to CodeViewDebug. |
665 | 728 | Target->Options.ObjectFilenameForDebug = Out->outputFilename(); |
666 | 729 |
|
| 730 | + // Return a copy of the output filename via the output param |
| 731 | + OutputFilename = Out->outputFilename(); |
| 732 | + |
667 | 733 | // Tell target that this tool is not necessarily used with argument ABI |
668 | 734 | // compliance (i.e. narrow integer argument extensions). |
669 | 735 | Target->Options.VerifyArgABICompliance = 0; |
|
0 commit comments