Skip to content

Commit e724eba

Browse files
committed
[Remarks] Add a specialized RemarkStreamer for SIL remarks
This allows the usage of the whole remark infrastructure developed in LLVM, which includes a new binary format, metadata in object files, etc. This gets rid of the YAMLTraits-based remark serialization and does the plumbing for hooking to LLVM's main remark streamer. For more about the idea behind LLVM's main remark streamer, see the docs/Remarks.rst changes in https://reviews.llvm.org/D73676. The flags are now: * -save-optimization-record: enable remarks, defaults to YAML * -save-optimization-record=<format>: enable remarks, use <format> for serialization * -save-optimization-record-passes <regex>: only serialize passes that match <regex>. The YAMLTraits in swift had a different `flow` setting for the debug location, resulting in some test changes.
1 parent e7b2850 commit e724eba

29 files changed

+505
-230
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,8 @@ NOTE(compiled_module_invalid_reason,none,
372372
ERROR(unknown_forced_module_loading_mode,none,
373373
"unknown value for SWIFT_FORCE_MODULE_LOADING variable: '%0'",
374374
(StringRef))
375+
ERROR(error_creating_remark_serializer,none,
376+
"error while creating remark serializer: '%0'", (StringRef))
375377

376378
REMARK(interface_file_lock_failure,none,
377379
"could not acquire lock file for module interface '%0'", (StringRef))

include/swift/AST/SILOptions.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/Basic/OptimizationMode.h"
2424
#include "llvm/ADT/Hashing.h"
2525
#include "llvm/ADT/StringRef.h"
26+
#include "llvm/Remarks/RemarkFormat.h"
2627
#include <string>
2728
#include <climits>
2829

@@ -161,10 +162,17 @@ class SILOptions {
161162
/// pipeline or after serialization.
162163
bool StripOwnershipAfterSerialization = true;
163164

164-
/// The name of the file to which the backend should save YAML optimization
165+
/// The name of the file to which the backend should save optimization
165166
/// records.
166167
std::string OptRecordFile;
167168

169+
/// The regex that filters the passes that should be saved to the optimization
170+
/// records.
171+
std::string OptRecordPasses;
172+
173+
/// The format used for serializing remarks (default: YAML)
174+
llvm::remarks::Format OptRecordFormat = llvm::remarks::Format::YAML;
175+
168176
SILOptions() {}
169177

170178
/// Return a hash code of any components from these options that should

include/swift/Basic/FileTypes.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ TYPE("tbd", TBD, "tbd", "")
7272
TYPE("module-trace", ModuleTrace, "trace.json", "")
7373

7474
TYPE("index-data", IndexData, "", "")
75-
TYPE("opt-record", OptRecord, "opt.yaml", "")
75+
TYPE("yaml-opt-record", YAMLOptRecord, "opt.yaml", "")
76+
TYPE("bitstream-opt-record",BitstreamOptRecord, "opt.bitstream", "")
7677

7778
// Overlay files declare wrapper modules, called "separately-imported overlays",
7879
// that should be automatically imported when a particular module is imported.

include/swift/Driver/ToolChain.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,9 @@ class ToolChain {
317317
virtual void validateArguments(DiagnosticEngine &diags,
318318
const llvm::opt::ArgList &args,
319319
StringRef defaultTarget) const {}
320+
321+
llvm::Expected<file_types::ID>
322+
remarkFileTypeFromArgs(const llvm::opt::ArgList &Args) const;
320323
};
321324
} // end namespace driver
322325
} // end namespace swift

include/swift/Option/Options.td

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,10 +548,20 @@ def Rpass_missed_EQ : Joined<["-"], "Rpass-missed=">,
548548

549549
def save_optimization_record : Flag<["-"], "save-optimization-record">,
550550
Flags<[FrontendOption]>, HelpText<"Generate a YAML optimization record file">;
551+
def save_optimization_record_EQ : Joined<["-"], "save-optimization-record=">,
552+
Flags<[FrontendOption]>,
553+
HelpText<"Generate an optimization record file in a specific format "
554+
"(default: YAML)">, MetaVarName<"<format>">;
551555
def save_optimization_record_path :
552556
Separate<["-"], "save-optimization-record-path">,
553557
Flags<[FrontendOption, ArgumentIsPath]>,
554-
HelpText<"Specify the file name of any generated YAML optimization record">;
558+
HelpText<"Specify the file name of any generated optimization record">;
559+
def save_optimization_record_passes :
560+
Separate<["-"], "save-optimization-record-passes">,
561+
Flags<[FrontendOption]>,
562+
HelpText<"Only include passes which match a specified regular expression in"
563+
"the generated optimization record "
564+
"(by default, include all passes)">, MetaVarName<"<regex>">;
555565

556566
// Platform options.
557567
def enable_app_extension : Flag<["-"], "application-extension">,

include/swift/SIL/OptimizationRemark.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#define SWIFT_SIL_OPTIMIZATIONREMARKEMITTER_H
2121

2222
#include "swift/Basic/SourceLoc.h"
23+
#include "swift/Demangling/Demangler.h"
2324
#include "swift/SIL/SILBasicBlock.h"
2425
#include "swift/SIL/SILInstruction.h"
2526
#include "swift/SIL/SILModule.h"
@@ -75,23 +76,30 @@ template <typename DerivedT> class Remark {
7576
StringRef passName;
7677

7778
/// Textual identifier for the remark (single-word, camel-case). Can be used
78-
/// by external tools reading the YAML output file for optimization remarks to
79+
/// by external tools reading the output file for optimization remarks to
7980
/// identify the remark.
80-
StringRef identifier;
81+
SmallString<32> identifier;
8182

8283
/// Source location for the diagnostics.
8384
SourceLoc location;
8485

8586
/// The function for the diagnostics.
8687
SILFunction *function;
8788

89+
/// The demangled name of \p Function.
90+
SmallString<64> demangledFunctionName;
91+
8892
/// Indentation used if this remarks is printed as a debug message.
8993
unsigned indentDebugWidth = 0;
9094

9195
protected:
9296
Remark(StringRef identifier, SILInstruction &i)
93-
: identifier(identifier), location(i.getLoc().getSourceLoc()),
94-
function(i.getParent()->getParent()) {}
97+
: identifier((Twine("sil.") + identifier).str()),
98+
location(i.getLoc().getSourceLoc()),
99+
function(i.getParent()->getParent()),
100+
demangledFunctionName(Demangle::demangleSymbolAsString(
101+
function->getName(),
102+
Demangle::DemangleOptions::SimplifiedUIDemangleOptions())) {}
95103

96104
public:
97105
DerivedT &operator<<(StringRef s) {
@@ -112,11 +120,13 @@ template <typename DerivedT> class Remark {
112120
StringRef getPassName() const { return passName; }
113121
StringRef getIdentifier() const { return identifier; }
114122
SILFunction *getFunction() const { return function; }
123+
StringRef getDemangledFunctionName() const { return demangledFunctionName; }
115124
SourceLoc getLocation() const { return location; }
116125
std::string getMsg() const;
117126
std::string getDebugMsg() const;
118127
Remark<DerivedT> &getRemark() { return *this; }
119128
SmallVector<Argument, 4> &getArgs() { return args; }
129+
ArrayRef<Argument> getArgs() const { return args; }
120130

121131
void setPassName(StringRef name) { passName = name; }
122132
};
@@ -156,7 +166,7 @@ class Emitter {
156166
void emit(T remarkBuilder, decltype(remarkBuilder()) * = nullptr) {
157167
using RemarkT = decltype(remarkBuilder());
158168
// Avoid building the remark unless remarks are enabled.
159-
if (isEnabled<RemarkT>() || module.getOptRecordStream()) {
169+
if (isEnabled<RemarkT>() || module.getSILRemarkStreamer()) {
160170
auto rb = remarkBuilder();
161171
rb.setPassName(passName);
162172
emit(rb);
@@ -171,7 +181,7 @@ class Emitter {
171181
using RemarkT = decltype(remarkBuilder());
172182
// Avoid building the remark unless remarks are enabled.
173183
bool emitRemark = emitter && (emitter->isEnabled<RemarkT>() ||
174-
emitter->module.getOptRecordStream());
184+
emitter->module.getSILRemarkStreamer());
175185
// Same for DEBUG.
176186
bool shouldEmitDebug = false;
177187
#ifndef NDEBUG

include/swift/SIL/SILModule.h

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class SILUndef;
6767
class SourceFile;
6868
class SerializedSILLoader;
6969
class SILFunctionBuilder;
70+
class SILRemarkStreamer;
7071

7172
namespace Lowering {
7273
class SILGenModule;
@@ -232,13 +233,11 @@ class SILModule {
232233
// The list of SILProperties in the module.
233234
PropertyListType properties;
234235

235-
/// This is the underlying raw stream of OptRecordStream.
236-
///
237-
/// It is also owned by SILModule in order to keep their lifetime in sync.
238-
std::unique_ptr<llvm::raw_ostream> OptRecordRawStream;
236+
/// The remark output stream used to record SIL remarks to a file.
237+
std::unique_ptr<llvm::raw_fd_ostream> silRemarkStream;
239238

240-
/// If non-null, the YAML file where remarks should be recorded.
241-
std::unique_ptr<llvm::yaml::Output> OptRecordStream;
239+
/// The remark streamer used to serialize SIL remarks to a file.
240+
std::unique_ptr<swift::SILRemarkStreamer> silRemarkStreamer;
242241

243242
/// This is a cache of intrinsic Function declarations to numeric ID mappings.
244243
llvm::DenseMap<Identifier, IntrinsicInfo> IntrinsicIDCache;
@@ -524,9 +523,12 @@ class SILModule {
524523
return coverageMaps;
525524
}
526525

527-
llvm::yaml::Output *getOptRecordStream() { return OptRecordStream.get(); }
528-
void setOptRecordStream(std::unique_ptr<llvm::yaml::Output> &&Stream,
529-
std::unique_ptr<llvm::raw_ostream> &&RawStream);
526+
swift::SILRemarkStreamer *getSILRemarkStreamer() {
527+
return silRemarkStreamer.get();
528+
}
529+
void setSILRemarkStreamer(
530+
std::unique_ptr<llvm::raw_fd_ostream> &&remarkStream,
531+
std::unique_ptr<swift::SILRemarkStreamer> &&remarkStreamer);
530532

531533
// This is currently limited to VarDecl because the visibility of global
532534
// variables and class properties is straightforward, while the visibility of

include/swift/SIL/SILRemarkStreamer.h

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//===--- SILRemarkStreamer.h - Interface for streaming remarks --*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
/// \file
14+
/// This file defines the interface used to stream SIL optimization diagnostics
15+
/// through LLVM's RemarkStreamer interface.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#ifndef SWIFT_SIL_SILREMARKSTREAMER_H
20+
#define SWIFT_SIL_SILREMARKSTREAMER_H
21+
22+
#include "swift/SIL/OptimizationRemark.h"
23+
#include "llvm/Remarks/RemarkStreamer.h"
24+
25+
namespace swift {
26+
27+
class SILRemarkStreamer {
28+
llvm::remarks::RemarkStreamer &llvmStreamer;
29+
// Source manager for resolving source locations.
30+
const SourceManager &srcMgr;
31+
/// Convert diagnostics into LLVM remark objects.
32+
/// The lifetime of the members of the result is bound to the lifetime of
33+
/// the SIL remarks.
34+
template <typename RemarkT>
35+
llvm::remarks::Remark
36+
toLLVMRemark(const OptRemark::Remark<RemarkT> &remark) const;
37+
38+
public:
39+
SILRemarkStreamer(llvm::remarks::RemarkStreamer &llvmStreamer,
40+
const SourceManager &srcMgr)
41+
: llvmStreamer(llvmStreamer), srcMgr(srcMgr) {}
42+
/// Emit a remark through the streamer.
43+
template <typename RemarkT>
44+
void emit(const OptRemark::Remark<RemarkT> &remark);
45+
};
46+
47+
std::pair<std::unique_ptr<llvm::raw_fd_ostream>,
48+
std::unique_ptr<SILRemarkStreamer>>
49+
createSILRemarkStreamer(SILModule &srcMgr, StringRef filename, StringRef passes,
50+
llvm::remarks::Format format,
51+
DiagnosticEngine &diagEngine, SourceManager &sourceMgr);
52+
53+
// Implementation for template member functions.
54+
55+
// OptRemark type -> llvm::remarks::Type
56+
template <typename RemarkT> static llvm::remarks::Type toRemarkType() {
57+
if (std::is_same<RemarkT, OptRemark::RemarkPassed>::value)
58+
return llvm::remarks::Type::Passed;
59+
if (std::is_same<RemarkT, OptRemark::RemarkMissed>::value)
60+
return llvm::remarks::Type::Missed;
61+
llvm_unreachable("Unknown remark type");
62+
}
63+
64+
static inline Optional<llvm::remarks::RemarkLocation>
65+
toRemarkLocation(const SourceLoc &loc, const SourceManager &srcMgr) {
66+
if (!loc.isValid())
67+
return None;
68+
69+
StringRef file = srcMgr.getDisplayNameForLoc(loc);
70+
unsigned line, col;
71+
std::tie(line, col) = srcMgr.getLineAndColumn(loc);
72+
return llvm::remarks::RemarkLocation{file, line, col};
73+
}
74+
75+
template <typename RemarkT>
76+
llvm::remarks::Remark SILRemarkStreamer::toLLVMRemark(
77+
const OptRemark::Remark<RemarkT> &optRemark) const {
78+
llvm::remarks::Remark llvmRemark; // The result.
79+
llvmRemark.RemarkType = toRemarkType<RemarkT>();
80+
llvmRemark.PassName = optRemark.getPassName();
81+
llvmRemark.RemarkName = optRemark.getIdentifier();
82+
llvmRemark.FunctionName = optRemark.getDemangledFunctionName();
83+
llvmRemark.Loc = toRemarkLocation(optRemark.getLocation(), srcMgr);
84+
85+
for (const OptRemark::Argument &arg : optRemark.getArgs()) {
86+
llvmRemark.Args.emplace_back();
87+
llvmRemark.Args.back().Key = arg.key;
88+
llvmRemark.Args.back().Val = arg.val;
89+
llvmRemark.Args.back().Loc = toRemarkLocation(arg.loc, srcMgr);
90+
}
91+
92+
return llvmRemark;
93+
}
94+
95+
template <typename RemarkT>
96+
void SILRemarkStreamer::emit(const OptRemark::Remark<RemarkT> &optRemark) {
97+
if (!llvmStreamer.matchesFilter(optRemark.getPassName()))
98+
return;
99+
100+
return llvmStreamer.getSerializer().emit(toLLVMRemark(optRemark));
101+
}
102+
103+
} // namespace swift
104+
#endif

lib/Basic/FileTypes.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ bool file_types::isTextual(ID Id) {
7878
case file_types::TY_ImportedModules:
7979
case file_types::TY_TBD:
8080
case file_types::TY_ModuleTrace:
81-
case file_types::TY_OptRecord:
81+
case file_types::TY_YAMLOptRecord:
8282
case file_types::TY_SwiftModuleInterfaceFile:
8383
case file_types::TY_PrivateSwiftModuleInterfaceFile:
8484
case file_types::TY_SwiftOverlayFile:
@@ -102,6 +102,7 @@ bool file_types::isTextual(ID Id) {
102102
case file_types::TY_Nothing:
103103
case file_types::TY_Remapping:
104104
case file_types::TY_IndexData:
105+
case file_types::TY_BitstreamOptRecord:
105106
return false;
106107
case file_types::TY_INVALID:
107108
llvm_unreachable("Invalid type ID.");
@@ -146,7 +147,8 @@ bool file_types::isAfterLLVM(ID Id) {
146147
case file_types::TY_Remapping:
147148
case file_types::TY_IndexData:
148149
case file_types::TY_ModuleTrace:
149-
case file_types::TY_OptRecord:
150+
case file_types::TY_YAMLOptRecord:
151+
case file_types::TY_BitstreamOptRecord:
150152
case file_types::TY_SwiftModuleInterfaceFile:
151153
case file_types::TY_PrivateSwiftModuleInterfaceFile:
152154
return false;
@@ -195,7 +197,8 @@ bool file_types::isPartOfSwiftCompilation(ID Id) {
195197
case file_types::TY_Remapping:
196198
case file_types::TY_IndexData:
197199
case file_types::TY_ModuleTrace:
198-
case file_types::TY_OptRecord:
200+
case file_types::TY_YAMLOptRecord:
201+
case file_types::TY_BitstreamOptRecord:
199202
return false;
200203
case file_types::TY_INVALID:
201204
llvm_unreachable("Invalid type ID.");

lib/Driver/Driver.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include "llvm/Option/Arg.h"
4848
#include "llvm/Option/ArgList.h"
4949
#include "llvm/Option/OptTable.h"
50+
#include "llvm/Remarks/RemarkFormat.h"
5051
#include "llvm/Support/Debug.h"
5152
#include "llvm/Support/ErrorHandling.h"
5253
#include "llvm/Support/FileSystem.h"
@@ -1941,7 +1942,8 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
19411942
case file_types::TY_ImportedModules:
19421943
case file_types::TY_TBD:
19431944
case file_types::TY_ModuleTrace:
1944-
case file_types::TY_OptRecord:
1945+
case file_types::TY_YAMLOptRecord:
1946+
case file_types::TY_BitstreamOptRecord:
19451947
case file_types::TY_SwiftModuleInterfaceFile:
19461948
case file_types::TY_PrivateSwiftModuleInterfaceFile:
19471949
case file_types::TY_SwiftCrossImportDir:
@@ -2766,6 +2768,7 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA,
27662768
Output.get());
27672769

27682770
if (C.getArgs().hasArg(options::OPT_save_optimization_record,
2771+
options::OPT_save_optimization_record_EQ,
27692772
options::OPT_save_optimization_record_path))
27702773
chooseOptimizationRecordPath(C, workingDirectory, Buf, Output.get());
27712774

@@ -3202,12 +3205,18 @@ void Driver::chooseOptimizationRecordPath(Compilation &C,
32023205
CommandOutput *Output) const {
32033206
const OutputInfo &OI = C.getOutputInfo();
32043207
if (OI.CompilerMode == OutputInfo::Mode::SingleCompile) {
3208+
llvm::Expected<file_types::ID> FileType =
3209+
C.getToolChain().remarkFileTypeFromArgs(C.getArgs());
3210+
if (!FileType) {
3211+
Diags.diagnose({}, diag::error_creating_remark_serializer,
3212+
llvm::toString(FileType.takeError()));
3213+
return;
3214+
}
32053215
auto filename = *getOutputFilenameFromPathArgOrAsTopLevel(
3206-
OI, C.getArgs(), options::OPT_save_optimization_record_path,
3207-
file_types::TY_OptRecord, /*TreatAsTopLevelOutput=*/true,
3208-
workingDirectory, Buf);
3216+
OI, C.getArgs(), options::OPT_save_optimization_record_path, *FileType,
3217+
/*TreatAsTopLevelOutput=*/true, workingDirectory, Buf);
32093218

3210-
Output->setAdditionalOutputForType(file_types::TY_OptRecord, filename);
3219+
Output->setAdditionalOutputForType(*FileType, filename);
32113220
} else
32123221
// FIXME: We should use the OutputMap in this case.
32133222
Diags.diagnose({}, diag::warn_opt_remark_disabled);

0 commit comments

Comments
 (0)