Skip to content

Commit 328a2e4

Browse files
committed
[tools][llc] Add --save-stats option (llvm#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. (chery-pick 96a5289)
1 parent 35f4830 commit 328a2e4

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
@@ -136,6 +136,12 @@ End-user Options
136136

137137
Print statistics recorded by code-generation passes.
138138

139+
.. option:: --save-stats, --save-stats=cwd, --save-stats=obj
140+
141+
Save LLVM statistics to a file in the current directory
142+
(:option:`--save-stats`/"--save-stats=cwd") or the directory
143+
of the output file ("--save-stats=obj") in JSON format.
144+
139145
.. option:: --time-passes
140146

141147
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
@@ -297,6 +297,7 @@ Changes to the LLVM tools
297297
([#47468](https://github.com/llvm/llvm-project/issues/47468))
298298
* llvm-addr2line now supports a `+` prefix when specifying an address.
299299
* Support for `SHT_LLVM_BB_ADDR_MAP` versions 0 and 1 has been dropped.
300+
* Add `--save-stats` option to `llc` to save LLVM statistics to a file. Compatible with the Clang option.
300301

301302
Changes to LLDB
302303
---------------------------------

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/CAS/ObjectStore.h"
2021
#include "llvm/CodeGen/CommandFlags.h"
@@ -45,6 +46,7 @@
4546
#include "llvm/Support/FileSystem.h"
4647
#include "llvm/Support/FormattedStream.h"
4748
#include "llvm/Support/InitLLVM.h"
49+
#include "llvm/Support/Path.h"
4850
#include "llvm/Support/PluginLoader.h"
4951
#include "llvm/Support/Process.h"
5052
#include "llvm/Support/SourceMgr.h"
@@ -58,6 +60,7 @@
5860
#include "llvm/TargetParser/SubtargetFeature.h"
5961
#include "llvm/TargetParser/Triple.h"
6062
#include "llvm/Transforms/Utils/Cloning.h"
63+
#include <cassert>
6164
#include <memory>
6265
#include <optional>
6366
using namespace llvm;
@@ -200,6 +203,20 @@ static cl::opt<std::string> RemarksFormat(
200203
cl::desc("The format used for serializing remarks (default: YAML)"),
201204
cl::value_desc("format"), cl::init("yaml"));
202205

206+
enum SaveStatsMode { None, Cwd, Obj };
207+
208+
static cl::opt<SaveStatsMode> SaveStats(
209+
"save-stats",
210+
cl::desc("Save LLVM statistics to a file in the current directory"
211+
"(`-save-stats`/`-save-stats=cwd`) or the directory of the output"
212+
"file (`-save-stats=obj`). (default: cwd)"),
213+
cl::values(clEnumValN(SaveStatsMode::Cwd, "cwd",
214+
"Save to the current working directory"),
215+
clEnumValN(SaveStatsMode::Cwd, "", ""),
216+
clEnumValN(SaveStatsMode::Obj, "obj",
217+
"Save to the output file directory")),
218+
cl::init(SaveStatsMode::None), cl::ValueOptional);
219+
203220
static cl::opt<bool> EnableNewPassManager(
204221
"enable-new-pm", cl::desc("Enable the new pass manager"), cl::init(false));
205222

@@ -262,7 +279,8 @@ static cl::opt<RunPassOption, true, cl::parser<std::string>> RunPass(
262279
cl::desc("Run compiler only for specified passes (comma separated list)"),
263280
cl::value_desc("pass-name"), cl::location(RunPassOpt));
264281

265-
static int compileModule(char **, LLVMContext &);
282+
static int compileModule(char **argv, LLVMContext &Context,
283+
std::string &OutputFilename);
266284

267285
[[noreturn]] static void reportError(Twine Msg, StringRef Filename = "") {
268286
SmallString<256> Prefix;
@@ -373,6 +391,45 @@ static void verifyCASOptions(const Triple &TheTriple) {
373391
}
374392
// END MCCAS
375393

394+
static int MaybeEnableStats() {
395+
if (SaveStats == SaveStatsMode::None)
396+
return 0;
397+
398+
llvm::EnableStatistics(false);
399+
return 0;
400+
}
401+
402+
static int MaybeSaveStats(std::string &&OutputFilename) {
403+
if (SaveStats == SaveStatsMode::None)
404+
return 0;
405+
406+
SmallString<128> StatsFilename;
407+
if (SaveStats == SaveStatsMode::Obj) {
408+
StatsFilename = OutputFilename;
409+
llvm::sys::path::remove_filename(StatsFilename);
410+
} else {
411+
assert(SaveStats == SaveStatsMode::Cwd &&
412+
"Should have been a valid --save-stats value");
413+
}
414+
415+
auto BaseName = llvm::sys::path::filename(OutputFilename);
416+
llvm::sys::path::append(StatsFilename, BaseName);
417+
llvm::sys::path::replace_extension(StatsFilename, "stats");
418+
419+
auto FileFlags = llvm::sys::fs::OF_TextWithCRLF;
420+
std::error_code EC;
421+
auto StatsOS =
422+
std::make_unique<llvm::raw_fd_ostream>(StatsFilename, EC, FileFlags);
423+
if (EC) {
424+
WithColor::error(errs(), "llc")
425+
<< "Unable to open statistics file: " << EC.message() << "\n";
426+
return 1;
427+
}
428+
429+
llvm::PrintStatisticsJSON(*StatsOS);
430+
return 0;
431+
}
432+
376433
// main - Entry point for the llc compiler.
377434
//
378435
int main(int argc, char **argv) {
@@ -450,18 +507,23 @@ int main(int argc, char **argv) {
450507
reportError(std::move(E), RemarksFilename);
451508
std::unique_ptr<ToolOutputFile> RemarksFile = std::move(*RemarksFileOrErr);
452509

510+
if (int RetVal = MaybeEnableStats())
511+
return RetVal;
512+
std::string OutputFilename;
513+
453514
if (InputLanguage != "" && InputLanguage != "ir" && InputLanguage != "mir")
454515
reportError("input language must be '', 'IR' or 'MIR'");
455516

456517
// Compile the module TimeCompilations times to give better compile time
457518
// metrics.
458519
for (unsigned I = TimeCompilations; I; --I)
459-
if (int RetVal = compileModule(argv, Context))
520+
if (int RetVal = compileModule(argv, Context, OutputFilename))
460521
return RetVal;
461522

462523
if (RemarksFile)
463524
RemarksFile->keep();
464-
return 0;
525+
526+
return MaybeSaveStats(std::move(OutputFilename));
465527
}
466528

467529
static bool addPass(PassManagerBase &PM, const char *argv0,
@@ -493,7 +555,8 @@ static bool addPass(PassManagerBase &PM, const char *argv0,
493555
return false;
494556
}
495557

496-
static int compileModule(char **argv, LLVMContext &Context) {
558+
static int compileModule(char **argv, LLVMContext &Context,
559+
std::string &OutputFilename) {
497560
// Load the module to be compiled...
498561
SMDiagnostic Err;
499562
std::unique_ptr<Module> M;
@@ -678,6 +741,9 @@ static int compileModule(char **argv, LLVMContext &Context) {
678741
// Ensure the filename is passed down to CodeViewDebug.
679742
Target->Options.ObjectFilenameForDebug = Out->outputFilename();
680743

744+
// Return a copy of the output filename via the output param
745+
OutputFilename = Out->outputFilename();
746+
681747
// Tell target that this tool is not necessarily used with argument ABI
682748
// compliance (i.e. narrow integer argument extensions).
683749
Target->Options.VerifyArgABICompliance = 0;

0 commit comments

Comments
 (0)