Skip to content

Commit 96a5289

Browse files
authored
[tools][llc] Add --save-stats option (#163967)
This patch adds a Clang-compatible `--save-stats` option, to provide an easy to use way to save LLVM statistics files when working with llc on the backend. Like on Clang, one can specify `--save-stats`, `--save-stats=cwd`, and `--save-stats=obj` with the same semantics and JSON format. The implementation uses 2 methods `MaybeEnableStats` and `MaybeSaveStats` called before and after `compileModule` respectively that externally own the statistics related logic, while `compileModule` is now required to return the resolved output filename via an output param. Note: like on Clang, the pre-existing `--stats` option is not affected.
1 parent 93d445c commit 96a5289

File tree

4 files changed

+92
-4
lines changed

4 files changed

+92
-4
lines changed

llvm/docs/CommandGuide/llc.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ End-user Options
129129

130130
Print statistics recorded by code-generation passes.
131131

132+
.. option:: --save-stats, --save-stats=cwd, --save-stats=obj
133+
134+
Save LLVM statistics to a file in the current directory
135+
(:option:`--save-stats`/"--save-stats=cwd") or the directory
136+
of the output file ("--save-stats=obj") in JSON format.
137+
132138
.. option:: --time-passes
133139

134140
Record the amount of time needed for each pass and print a report to standard

llvm/docs/ReleaseNotes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ Changes to the LLVM tools
182182
* `llvm-readelf` now dumps all hex format values in lower-case mode.
183183
* Some code paths for supporting Python 2.7 in `llvm-lit` have been removed.
184184
* Support for `%T` in lit has been removed.
185+
* Add `--save-stats` option to `llc` to save LLVM statistics to a file. Compatible with the Clang option.
185186

186187
* `llvm-config` gained a new flag `--quote-paths` which quotes and escapes paths
187188
emitted on stdout, to account for spaces or other special characters in path.

llvm/test/tools/llc/save-stats.ll

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
; REQUIRES: asserts
2+
3+
; RUN: llc -mtriple=arm64-apple-macosx --save-stats=obj -o %t.s %s && cat %t.stats | FileCheck %s
4+
; RUN: llc -mtriple=arm64-apple-macosx --save-stats=cwd -o %t.s %s && cat %{t:stem}.tmp.stats | FileCheck %s
5+
; RUN: llc -mtriple=arm64-apple-macosx --save-stats -o %t.s %s && cat %{t:stem}.tmp.stats | FileCheck %s
6+
; RUN: not llc -mtriple=arm64-apple-macosx --save-stats=invalid -o %t.s %s 2>&1 | FileCheck %s --check-prefix=INVALID_ARG
7+
8+
; CHECK: {
9+
; CHECK: "asm-printer.EmittedInsts":
10+
; CHECK: }
11+
12+
; INVALID_ARG: {{.*}}llc{{.*}}: for the --save-stats option: Cannot find option named 'invalid'!
13+
define i32 @func() {
14+
ret i32 0
15+
}

llvm/tools/llc/llc.cpp

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "NewPMDriver.h"
1616
#include "llvm/ADT/STLExtras.h"
1717
#include "llvm/ADT/ScopeExit.h"
18+
#include "llvm/ADT/Statistic.h"
1819
#include "llvm/Analysis/TargetLibraryInfo.h"
1920
#include "llvm/CodeGen/CommandFlags.h"
2021
#include "llvm/CodeGen/LinkAllAsmWriterComponents.h"
@@ -45,6 +46,7 @@
4546
#include "llvm/Support/FormattedStream.h"
4647
#include "llvm/Support/InitLLVM.h"
4748
#include "llvm/Support/PGOOptions.h"
49+
#include "llvm/Support/Path.h"
4850
#include "llvm/Support/PluginLoader.h"
4951
#include "llvm/Support/SourceMgr.h"
5052
#include "llvm/Support/TargetSelect.h"
@@ -57,6 +59,7 @@
5759
#include "llvm/TargetParser/SubtargetFeature.h"
5860
#include "llvm/TargetParser/Triple.h"
5961
#include "llvm/Transforms/Utils/Cloning.h"
62+
#include <cassert>
6063
#include <memory>
6164
#include <optional>
6265
using namespace llvm;
@@ -208,6 +211,20 @@ static cl::opt<std::string> RemarksFormat(
208211
cl::desc("The format used for serializing remarks (default: YAML)"),
209212
cl::value_desc("format"), cl::init("yaml"));
210213

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+
211228
static cl::opt<bool> EnableNewPassManager(
212229
"enable-new-pm", cl::desc("Enable the new pass manager"), cl::init(false));
213230

@@ -281,7 +298,8 @@ static void setPGOOptions(TargetMachine &TM) {
281298
TM.setPGOOption(PGOOpt);
282299
}
283300

284-
static int compileModule(char **, LLVMContext &);
301+
static int compileModule(char **argv, LLVMContext &Context,
302+
std::string &OutputFilename);
285303

286304
[[noreturn]] static void reportError(Twine Msg, StringRef Filename = "") {
287305
SmallString<256> Prefix;
@@ -360,6 +378,45 @@ static std::unique_ptr<ToolOutputFile> GetOutputStream(const char *TargetName,
360378
return FDOut;
361379
}
362380

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+
363420
// main - Entry point for the llc compiler.
364421
//
365422
int main(int argc, char **argv) {
@@ -437,18 +494,23 @@ int main(int argc, char **argv) {
437494
reportError(std::move(E), RemarksFilename);
438495
LLVMRemarkFileHandle RemarksFile = std::move(*RemarksFileOrErr);
439496

497+
if (int RetVal = MaybeEnableStats())
498+
return RetVal;
499+
std::string OutputFilename;
500+
440501
if (InputLanguage != "" && InputLanguage != "ir" && InputLanguage != "mir")
441502
reportError("input language must be '', 'IR' or 'MIR'");
442503

443504
// Compile the module TimeCompilations times to give better compile time
444505
// metrics.
445506
for (unsigned I = TimeCompilations; I; --I)
446-
if (int RetVal = compileModule(argv, Context))
507+
if (int RetVal = compileModule(argv, Context, OutputFilename))
447508
return RetVal;
448509

449510
if (RemarksFile)
450511
RemarksFile->keep();
451-
return 0;
512+
513+
return MaybeSaveStats(std::move(OutputFilename));
452514
}
453515

454516
static bool addPass(PassManagerBase &PM, const char *argv0, StringRef PassName,
@@ -480,7 +542,8 @@ static bool addPass(PassManagerBase &PM, const char *argv0, StringRef PassName,
480542
return false;
481543
}
482544

483-
static int compileModule(char **argv, LLVMContext &Context) {
545+
static int compileModule(char **argv, LLVMContext &Context,
546+
std::string &OutputFilename) {
484547
// Load the module to be compiled...
485548
SMDiagnostic Err;
486549
std::unique_ptr<Module> M;
@@ -664,6 +727,9 @@ static int compileModule(char **argv, LLVMContext &Context) {
664727
// Ensure the filename is passed down to CodeViewDebug.
665728
Target->Options.ObjectFilenameForDebug = Out->outputFilename();
666729

730+
// Return a copy of the output filename via the output param
731+
OutputFilename = Out->outputFilename();
732+
667733
// Tell target that this tool is not necessarily used with argument ABI
668734
// compliance (i.e. narrow integer argument extensions).
669735
Target->Options.VerifyArgABICompliance = 0;

0 commit comments

Comments
 (0)