Merge pull request #12585 from anemet/save-opt-record

This commit is contained in:
swift-ci
2017-10-27 11:09:50 -07:00
committed by GitHub
17 changed files with 311 additions and 27 deletions

View File

@@ -136,6 +136,11 @@ WARNING(verify_debug_info_requires_debug_option,none,
ERROR(error_profile_missing,none, ERROR(error_profile_missing,none,
"no profdata file exists at '%0'", (StringRef)) "no profdata file exists at '%0'", (StringRef))
WARNING(warn_opt_remark_disabled, none,
"Emission of optimization records has been disabled, because it "
"requires a single compiler invocation: consider enabling the "
"-whole-module-optimization flag", ())
#ifndef DIAG_NO_UNDEF #ifndef DIAG_NO_UNDEF
# if defined(DIAG) # if defined(DIAG)
# undef DIAG # undef DIAG

View File

@@ -150,6 +150,10 @@ public:
/// \brief Enable large loadable types IRGen pass. /// \brief Enable large loadable types IRGen pass.
bool EnableLargeLoadableTypes = true; bool EnableLargeLoadableTypes = true;
/// The name of the file to which the backend should save YAML optimization
/// records.
std::string OptRecordFile;
SILOptions() {} SILOptions() {}
/// Return a hash code of any components from these options that should /// Return a hash code of any components from these options that should

View File

@@ -61,6 +61,7 @@ TYPE("imported-modules", ImportedModules, "importedmodules", "")
TYPE("tbd", TBD, "tbd", "") TYPE("tbd", TBD, "tbd", "")
TYPE("module-trace", ModuleTrace, "trace.json", "") TYPE("module-trace", ModuleTrace, "trace.json", "")
TYPE("index-data", IndexData, "", "") TYPE("index-data", IndexData, "", "")
TYPE("opt-record", OptRecord, "opt.yaml", "")
// Misc types // Misc types
TYPE("pcm", ClangModuleFile, "pcm", "") TYPE("pcm", ClangModuleFile, "pcm", "")

View File

@@ -331,6 +331,13 @@ def Rpass_missed_EQ : Joined<["-"], "Rpass-missed=">,
HelpText<"Report missed transformations by optimization passes whose " HelpText<"Report missed transformations by optimization passes whose "
"name matches the given POSIX regular expression">; "name matches the given POSIX regular expression">;
def save_optimization_record : Flag<["-"], "save-optimization-record">,
Flags<[FrontendOption]>, HelpText<"Generate a YAML optimization record file">;
def save_optimization_record_path :
Separate<["-"], "save-optimization-record-path">,
Flags<[FrontendOption]>,
HelpText<"Specify the file name of any generated YAML optimization record">;
// Platform options. // Platform options.
def enable_app_extension : Flag<["-"], "application-extension">, def enable_app_extension : Flag<["-"], "application-extension">,
Flags<[FrontendOption, NoInteractiveOption]>, Flags<[FrontendOption, NoInteractiveOption]>,

View File

@@ -20,12 +20,13 @@
#define SWIFT_SIL_OPTIMIZATIONREMARKEMITTER_H #define SWIFT_SIL_OPTIMIZATIONREMARKEMITTER_H
#include "swift/Basic/SourceLoc.h" #include "swift/Basic/SourceLoc.h"
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
namespace swift { namespace swift {
class ASTContext;
class SILFunction; class SILFunction;
namespace OptRemark { namespace OptRemark {
@@ -60,6 +61,9 @@ template <typename DerivedT> class Remark {
/// Arguments collected via the streaming interface. /// Arguments collected via the streaming interface.
SmallVector<Argument, 4> Args; SmallVector<Argument, 4> Args;
/// The name of the pass generating the remark.
StringRef PassName;
/// Textual identifier for the remark (single-word, camel-case). Can be used /// Textual identifier for the remark (single-word, camel-case). Can be used
/// by external tools reading the YAML output file for optimization remarks to /// by external tools reading the YAML output file for optimization remarks to
/// identify the remark. /// identify the remark.
@@ -68,9 +72,13 @@ template <typename DerivedT> class Remark {
/// Source location for the diagnostics. /// Source location for the diagnostics.
SourceLoc Location; SourceLoc Location;
/// The function for the diagnostics.
SILFunction *Function;
protected: protected:
Remark(StringRef Identifier, SILInstruction &I) Remark(StringRef Identifier, SILInstruction &I)
: Identifier(Identifier), Location(I.getLoc().getSourceLoc()) {} : Identifier(Identifier), Location(I.getLoc().getSourceLoc()),
Function(I.getParent()->getParent()) {}
public: public:
DerivedT &operator<<(StringRef S) { DerivedT &operator<<(StringRef S) {
@@ -83,8 +91,15 @@ public:
return *static_cast<DerivedT *>(this); return *static_cast<DerivedT *>(this);
} }
StringRef getPassName() const { return PassName; }
StringRef getIdentifier() const { return Identifier; }
SILFunction *getFunction() const { return Function; }
SourceLoc getLocation() const { return Location; } SourceLoc getLocation() const { return Location; }
std::string getMsg() const; std::string getMsg() const;
Remark<DerivedT> &getRemark() { return *this; }
SmallVector<Argument, 4> &getArgs() { return Args; }
void setPassName(StringRef PN) { PassName = PN; }
}; };
/// Remark to report a successful optimization. /// Remark to report a successful optimization.
@@ -99,7 +114,7 @@ struct RemarkMissed : public Remark<RemarkMissed> {
/// Used to emit the remarks. Passes reporting remarks should create an /// Used to emit the remarks. Passes reporting remarks should create an
/// instance of this. /// instance of this.
class Emitter { class Emitter {
ASTContext &Ctx; SILModule &Module;
std::string PassName; std::string PassName;
bool PassedEnabled; bool PassedEnabled;
bool MissedEnabled; bool MissedEnabled;
@@ -110,7 +125,7 @@ class Emitter {
template <typename RemarkT> bool isEnabled(); template <typename RemarkT> bool isEnabled();
public: public:
Emitter(StringRef PassName, ASTContext &Ctx); Emitter(StringRef PassName, SILModule &M);
/// \brief Take a lambda that returns a remark which will be emitted. The /// \brief Take a lambda that returns a remark which will be emitted. The
/// lambda is not evaluated unless remarks are enabled. Second argument is /// lambda is not evaluated unless remarks are enabled. Second argument is
@@ -119,8 +134,9 @@ public:
void emit(T RemarkBuilder, decltype(RemarkBuilder()) * = nullptr) { void emit(T RemarkBuilder, decltype(RemarkBuilder()) * = nullptr) {
using RemarkT = decltype(RemarkBuilder()); using RemarkT = decltype(RemarkBuilder());
// Avoid building the remark unless remarks are enabled. // Avoid building the remark unless remarks are enabled.
if (isEnabled<RemarkT>()) { if (isEnabled<RemarkT>() || Module.getOptRecordStream()) {
auto R = RemarkBuilder(); auto R = RemarkBuilder();
R.setPassName(PassName);
emit(R); emit(R);
} }
} }

View File

@@ -46,6 +46,12 @@
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include <functional> #include <functional>
namespace llvm {
namespace yaml {
class Output;
} // end namespace yaml
} // end namespace llvm
namespace swift { namespace swift {
class AnyFunctionType; class AnyFunctionType;
class ASTContext; class ASTContext;
@@ -178,6 +184,14 @@ private:
// The list of SILCoverageMaps in the module. // The list of SILCoverageMaps in the module.
CoverageMapListType coverageMaps; CoverageMapListType coverageMaps;
/// This is the underlying raw stream of OptRecordStream.
///
/// It is also owned by SILModule in order to keep their lifetime in sync.
std::unique_ptr<llvm::raw_ostream> OptRecordRawStream;
/// If non-null, the YAML file where remarks should be recorded.
std::unique_ptr<llvm::yaml::Output> OptRecordStream;
/// This is a cache of intrinsic Function declarations to numeric ID mappings. /// This is a cache of intrinsic Function declarations to numeric ID mappings.
llvm::DenseMap<Identifier, IntrinsicInfo> IntrinsicIDCache; llvm::DenseMap<Identifier, IntrinsicInfo> IntrinsicIDCache;
@@ -448,7 +462,11 @@ public:
} }
iterator_range<coverage_map_const_iterator> getCoverageMaps() const { iterator_range<coverage_map_const_iterator> getCoverageMaps() const {
return {coverageMaps.begin(), coverageMaps.end()}; return {coverageMaps.begin(), coverageMaps.end()};
} }
llvm::yaml::Output *getOptRecordStream() { return OptRecordStream.get(); }
void setOptRecordStream(std::unique_ptr<llvm::yaml::Output> &&Stream,
std::unique_ptr<llvm::raw_ostream> &&RawStream);
/// Look for a global variable by name. /// Look for a global variable by name.
/// ///

View File

@@ -1453,6 +1453,7 @@ void Driver::buildActions(SmallVectorImpl<const Action *> &TopLevelActions,
case types::TY_ImportedModules: case types::TY_ImportedModules:
case types::TY_TBD: case types::TY_TBD:
case types::TY_ModuleTrace: case types::TY_ModuleTrace:
case types::TY_OptRecord:
// We could in theory handle assembly or LLVM input, but let's not. // We could in theory handle assembly or LLVM input, but let's not.
// FIXME: What about LTO? // FIXME: What about LTO?
Diags.diagnose(SourceLoc(), diag::error_unexpected_input_file, Diags.diagnose(SourceLoc(), diag::error_unexpected_input_file,
@@ -2236,6 +2237,19 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA,
} }
} }
if (C.getArgs().hasArg(options::OPT_save_optimization_record,
options::OPT_save_optimization_record_path)) {
if (OI.CompilerMode == OutputInfo::Mode::SingleCompile) {
auto filename = *getOutputFilenameFromPathArgOrAsTopLevel(
OI, C.getArgs(), options::OPT_save_optimization_record_path,
types::TY_OptRecord, /*TreatAsTopLevelOutput=*/true, "opt.yaml", Buf);
Output->setAdditionalOutputForType(types::TY_OptRecord, filename);
} else
// FIXME: We should use the OutputMap in this case.
Diags.diagnose({}, diag::warn_opt_remark_disabled);
}
// Choose the Objective-C header output path. // Choose the Objective-C header output path.
if ((isa<MergeModuleJobAction>(JA) || if ((isa<MergeModuleJobAction>(JA) ||
(isa<CompileJobAction>(JA) && (isa<CompileJobAction>(JA) &&

View File

@@ -272,6 +272,7 @@ ToolChain::constructInvocation(const CompileJobAction &job,
case types::TY_SwiftDeps: case types::TY_SwiftDeps:
case types::TY_ModuleTrace: case types::TY_ModuleTrace:
case types::TY_TBD: case types::TY_TBD:
case types::TY_OptRecord:
llvm_unreachable("Output type can never be primary output."); llvm_unreachable("Output type can never be primary output.");
case types::TY_INVALID: case types::TY_INVALID:
llvm_unreachable("Invalid type ID"); llvm_unreachable("Invalid type ID");
@@ -448,6 +449,13 @@ ToolChain::constructInvocation(const CompileJobAction &job,
Arguments.push_back(TBDPath.c_str()); Arguments.push_back(TBDPath.c_str());
} }
const std::string &OptRecordPath =
context.Output.getAdditionalOutputForType(types::TY_OptRecord);
if (!OptRecordPath.empty()) {
Arguments.push_back("-save-optimization-record-path");
Arguments.push_back(OptRecordPath.c_str());
}
if (context.Args.hasArg(options::OPT_migrate_keep_objc_visibility)) { if (context.Args.hasArg(options::OPT_migrate_keep_objc_visibility)) {
Arguments.push_back("-migrate-keep-objc-visibility"); Arguments.push_back("-migrate-keep-objc-visibility");
} }
@@ -586,6 +594,7 @@ ToolChain::constructInvocation(const BackendJobAction &job,
case types::TY_SwiftDeps: case types::TY_SwiftDeps:
case types::TY_Remapping: case types::TY_Remapping:
case types::TY_ModuleTrace: case types::TY_ModuleTrace:
case types::TY_OptRecord:
llvm_unreachable("Output type can never be primary output."); llvm_unreachable("Output type can never be primary output.");
case types::TY_INVALID: case types::TY_INVALID:
llvm_unreachable("Invalid type ID"); llvm_unreachable("Invalid type ID");

View File

@@ -77,6 +77,7 @@ bool types::isTextual(ID Id) {
case types::TY_ImportedModules: case types::TY_ImportedModules:
case types::TY_TBD: case types::TY_TBD:
case types::TY_ModuleTrace: case types::TY_ModuleTrace:
case types::TY_OptRecord:
return true; return true;
case types::TY_Image: case types::TY_Image:
case types::TY_Object: case types::TY_Object:
@@ -131,6 +132,7 @@ bool types::isAfterLLVM(ID Id) {
case types::TY_Remapping: case types::TY_Remapping:
case types::TY_IndexData: case types::TY_IndexData:
case types::TY_ModuleTrace: case types::TY_ModuleTrace:
case types::TY_OptRecord:
return false; return false;
case types::TY_INVALID: case types::TY_INVALID:
llvm_unreachable("Invalid type ID."); llvm_unreachable("Invalid type ID.");
@@ -169,6 +171,7 @@ bool types::isPartOfSwiftCompilation(ID Id) {
case types::TY_Remapping: case types::TY_Remapping:
case types::TY_IndexData: case types::TY_IndexData:
case types::TY_ModuleTrace: case types::TY_ModuleTrace:
case types::TY_OptRecord:
return false; return false;
case types::TY_INVALID: case types::TY_INVALID:
llvm_unreachable("Invalid type ID."); llvm_unreachable("Invalid type ID.");

View File

@@ -1305,6 +1305,9 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
!Args.hasArg(OPT_disable_mandatory_semantic_arc_opts); !Args.hasArg(OPT_disable_mandatory_semantic_arc_opts);
Opts.EnableLargeLoadableTypes |= Args.hasArg(OPT_enable_large_loadable_types); Opts.EnableLargeLoadableTypes |= Args.hasArg(OPT_enable_large_loadable_types);
if (const Arg *A = Args.getLastArg(OPT_save_optimization_record_path))
Opts.OptRecordFile = A->getValue();
if (Args.hasArg(OPT_debug_on_sil)) { if (Args.hasArg(OPT_debug_on_sil)) {
// Derive the name of the SIL file for debugging from // Derive the name of the SIL file for debugging from
// the regular outputfile. // the regular outputfile.

View File

@@ -75,6 +75,7 @@
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h" #include "llvm/Support/Timer.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachine.h"
#include <memory> #include <memory>
@@ -507,6 +508,21 @@ static void countStatsPostSILOpt(UnifiedStatsReporter &Stats,
C.NumSILOptGlobalVariables = Module.getSILGlobalList().size(); C.NumSILOptGlobalVariables = Module.getSILGlobalList().size();
} }
static std::unique_ptr<llvm::raw_fd_ostream>
createOptRecordFile(StringRef Filename, DiagnosticEngine &DE) {
if (Filename.empty())
return nullptr;
std::error_code EC;
auto File = llvm::make_unique<llvm::raw_fd_ostream>(Filename, EC,
llvm::sys::fs::F_None);
if (EC) {
DE.diagnose(SourceLoc(), diag::cannot_open_file, Filename, EC.message());
return nullptr;
}
return File;
}
/// Performs the compile requested by the user. /// Performs the compile requested by the user.
/// \param Instance Will be reset after performIRGeneration when the verifier /// \param Instance Will be reset after performIRGeneration when the verifier
/// mode is NoVerify and there were no errors. /// mode is NoVerify and there were no errors.
@@ -748,9 +764,9 @@ static bool performCompile(CompilerInstance &Instance,
return Context.hadError(); return Context.hadError();
} }
const auto &SILOpts = Invocation.getSILOptions();
if (!opts.TBDPath.empty()) { if (!opts.TBDPath.empty()) {
const auto &silOpts = Invocation.getSILOptions(); auto hasMultipleIRGenThreads = SILOpts.NumThreads > 1;
auto hasMultipleIRGenThreads = silOpts.NumThreads > 1;
auto installName = opts.TBDInstallName.empty() auto installName = opts.TBDInstallName.empty()
? "lib" + Invocation.getModuleName().str() + ".dylib" ? "lib" + Invocation.getModuleName().str() + ".dylib"
: opts.TBDInstallName; : opts.TBDInstallName;
@@ -825,6 +841,13 @@ static bool performCompile(CompilerInstance &Instance,
return Context.hadError(); return Context.hadError();
} }
std::unique_ptr<llvm::raw_fd_ostream> OptRecordFile =
createOptRecordFile(SILOpts.OptRecordFile, Instance.getDiags());
if (OptRecordFile)
SM->setOptRecordStream(llvm::make_unique<llvm::yaml::Output>(
*OptRecordFile, &Instance.getSourceMgr()),
std::move(OptRecordFile));
// Perform "stable" optimizations that are invariant across compiler versions. // Perform "stable" optimizations that are invariant across compiler versions.
if (Action == FrontendOptions::MergeModules) { if (Action == FrontendOptions::MergeModules) {
// Don't run diagnostic passes at all. // Don't run diagnostic passes at all.
@@ -1059,8 +1082,8 @@ static bool performCompile(CompilerInstance &Instance,
!astGuaranteedToCorrespondToSIL) !astGuaranteedToCorrespondToSIL)
break; break;
const auto &silOpts = Invocation.getSILOptions(); const auto &SILOpts = Invocation.getSILOptions();
auto hasMultipleIRGenThreads = silOpts.NumThreads > 1; auto hasMultipleIRGenThreads = SILOpts.NumThreads > 1;
bool error; bool error;
if (PrimarySourceFile) if (PrimarySourceFile)
error = validateTBD(PrimarySourceFile, *IRModule, hasMultipleIRGenThreads, error = validateTBD(PrimarySourceFile, *IRModule, hasMultipleIRGenThreads,

View File

@@ -17,11 +17,10 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "swift/SIL/OptimizationRemark.h" #include "swift/SIL/OptimizationRemark.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsSIL.h" #include "swift/AST/DiagnosticsSIL.h"
#include "swift/SIL/SILFunction.h"
#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringExtras.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
using namespace swift; using namespace swift;
@@ -57,25 +56,93 @@ template <typename DerivedT> std::string Remark<DerivedT>::getMsg() const {
return OS.str(); return OS.str();
} }
Emitter::Emitter(StringRef PassName, ASTContext &Ctx) Emitter::Emitter(StringRef PassName, SILModule &M)
: Ctx(Ctx), PassName(PassName), : Module(M), PassName(PassName),
PassedEnabled( PassedEnabled(
Ctx.LangOpts.OptimizationRemarkPassedPattern && M.getASTContext().LangOpts.OptimizationRemarkPassedPattern &&
Ctx.LangOpts.OptimizationRemarkPassedPattern->match(PassName)), M.getASTContext().LangOpts.OptimizationRemarkPassedPattern->match(
PassName)),
MissedEnabled( MissedEnabled(
Ctx.LangOpts.OptimizationRemarkMissedPattern && M.getASTContext().LangOpts.OptimizationRemarkMissedPattern &&
Ctx.LangOpts.OptimizationRemarkMissedPattern->match(PassName)) {} M.getASTContext().LangOpts.OptimizationRemarkMissedPattern->match(
PassName)) {}
template <typename RemarkT, typename... ArgTypes> template <typename RemarkT, typename... ArgTypes>
static void emitRemark(ASTContext &Ctx, const RemarkT &R, static void emitRemark(SILModule &Module, const Remark<RemarkT> &R,
Diag<ArgTypes...> ID) { Diag<ArgTypes...> ID, bool DiagEnabled) {
Ctx.Diags.diagnose(R.getLocation(), ID, R.getMsg()); if (auto *Out = Module.getOptRecordStream())
// YAMLTraits takes a non-const reference even when outputting.
*Out << const_cast<Remark<RemarkT> &>(R);
if (DiagEnabled)
Module.getASTContext().Diags.diagnose(R.getLocation(), ID, R.getMsg());
} }
void Emitter::emit(const RemarkPassed &R) { void Emitter::emit(const RemarkPassed &R) {
emitRemark(Ctx, R, diag::opt_remark_passed); emitRemark(Module, R, diag::opt_remark_passed, isEnabled<RemarkPassed>());
} }
void Emitter::emit(const RemarkMissed &R) { void Emitter::emit(const RemarkMissed &R) {
emitRemark(Ctx, R, diag::opt_remark_missed); emitRemark(Module, R, diag::opt_remark_missed, isEnabled<RemarkMissed>());
} }
namespace llvm {
namespace yaml {
template <typename KindT> struct MappingTraits<Remark<KindT>> {
static void mapping(llvm::yaml::IO &io, Remark<KindT> &R) {
assert(io.outputting() && "input not implemented");
if (io.mapTag("!Passed", std::is_same<KindT, RemarkPassed>::value))
;
else if (io.mapTag("!Missed", std::is_same<KindT, RemarkMissed>::value))
;
else
llvm_unreachable("Unknown remark type");
// The attributes are read-only for now since we're only support outputting
// them.
StringRef PassName = R.getPassName();
io.mapRequired("Pass", PassName);
StringRef Id = R.getIdentifier();
io.mapRequired("Name", Id);
SourceLoc Loc = R.getLocation();
if (!io.outputting() || Loc.isValid())
io.mapOptional("DebugLoc", Loc);
StringRef FN = R.getFunction()->getName();
io.mapRequired("Function", FN);
io.mapOptional("Args", R.getArgs());
}
};
template <> struct MappingTraits<SourceLoc> {
static void mapping(IO &io, SourceLoc &Loc) {
assert(io.outputting() && "input not yet implemented");
SourceManager *SM = static_cast<SourceManager *>(io.getContext());
unsigned BufferID = SM->findBufferContainingLoc(Loc);
StringRef File = SM->getIdentifierForBuffer(BufferID);
unsigned Line, Col;
std::tie(Line, Col) = SM->getLineAndColumn(Loc, BufferID);
io.mapRequired("File", File);
io.mapRequired("Line", Line);
io.mapRequired("Column", Col);
}
};
// Implement this as a mapping for now to get proper quotation for the value.
template <> struct MappingTraits<OptRemark::Argument> {
static void mapping(IO &io, OptRemark::Argument &A) {
assert(io.outputting() && "input not yet implemented");
io.mapRequired(A.Key.data(), A.Val);
if (A.Loc.isValid())
io.mapOptional("DebugLoc", A.Loc);
}
};
} // end namespace yaml
} // end namespace llvm
LLVM_YAML_IS_SEQUENCE_VECTOR(OptRemark::Argument)

View File

@@ -27,6 +27,7 @@
#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Statistic.h" #include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
#include "llvm/Support/YAMLTraits.h"
#include <functional> #include <functional>
using namespace swift; using namespace swift;
using namespace Lowering; using namespace Lowering;
@@ -781,3 +782,9 @@ void SILModule::serialize() {
setSerialized(); setSerialized();
} }
void SILModule::setOptRecordStream(
std::unique_ptr<llvm::yaml::Output> &&Stream,
std::unique_ptr<llvm::raw_ostream> &&RawStream) {
OptRecordStream = std::move(Stream);
OptRecordRawStream = std::move(RawStream);
}

View File

@@ -897,8 +897,7 @@ public:
DominanceAnalysis *DA = PM->getAnalysis<DominanceAnalysis>(); DominanceAnalysis *DA = PM->getAnalysis<DominanceAnalysis>();
SILLoopAnalysis *LA = PM->getAnalysis<SILLoopAnalysis>(); SILLoopAnalysis *LA = PM->getAnalysis<SILLoopAnalysis>();
SideEffectAnalysis *SEA = PM->getAnalysis<SideEffectAnalysis>(); SideEffectAnalysis *SEA = PM->getAnalysis<SideEffectAnalysis>();
OptRemark::Emitter ORE(DEBUG_TYPE, OptRemark::Emitter ORE(DEBUG_TYPE, getFunction()->getModule());
getFunction()->getModule().getASTContext());
if (getOptions().InlineThreshold == 0) { if (getOptions().InlineThreshold == 0) {
return; return;

View File

@@ -0,0 +1,43 @@
// RUN: %empty-directory(%t)
// RUN: %target-swiftc_driver -O -wmo -save-optimization-record %s -module-name optrecordmod -o %t/opt-record 2>&1 | %FileCheck -allow-empty %s
// RUN: %FileCheck -check-prefix=YAML %s < %t/optrecordmod.opt.yaml
// RUN: %target-swiftc_driver -O -wmo -save-optimization-record-path %t/specified.opt.yaml %s -module-name optrecordmod -o %t/opt-record 2>&1 | %FileCheck -allow-empty %s
// RUN: %FileCheck -check-prefix=YAML %s < %t/specified.opt.yaml
// CHECK-NOT: remark
var a: Int = 1
func foo() {
a = 2
}
public func bar() {
// YAML: --- !Passed
// YAML-NEXT: Pass: sil-inliner
// YAML-NEXT: Name: Inlined
// YAML-NEXT: DebugLoc:
// YAML-NEXT: File: {{.*}}opt-record.swift
// YAML-NEXT: Line: 42
// YAML-NEXT: Column: 3
// YAML-NEXT: Function: _T012optrecordmod3baryyF
// YAML-NEXT: Args:
// YAML-NEXT: - Callee: _T012optrecordmod3fooyyF
// YAML-NEXT: DebugLoc:
// YAML-NEXT: File: {{.*}}opt-record.swift
// YAML-NEXT: Line: 11
// YAML-NEXT: Column: 6
// YAML-NEXT: - String: ' inlined into '
// YAML-NEXT: - Caller: _T012optrecordmod3baryyF
// YAML-NEXT: DebugLoc:
// YAML-NEXT: File: {{.*}}opt-record.swift
// YAML-NEXT: Line: 15
// YAML-NEXT: Column: 13
// YAML-NEXT: - String: ' (cost = '
// YAML-NEXT: - Cost: '{{.*}}'
// YAML-NEXT: - String: ', benefit = '
// YAML-NEXT: - Benefit: '{{.*}}'
// YAML-NEXT: - String: ')'
// YAML-NEXT: ...
foo()
}

View File

@@ -2,9 +2,12 @@
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -inline -sil-remarks=sil-inliner -o %t.sil 2>&1 | %FileCheck -check-prefix=REMARKS_PASSED %s // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -inline -sil-remarks=sil-inliner -o %t.sil 2>&1 | %FileCheck -check-prefix=REMARKS_PASSED %s
// RUN: %FileCheck %s < %t.sil // RUN: %FileCheck %s < %t.sil
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -inline -sil-remarks-missed=sil-inliner -o /dev/null 2>&1 | %FileCheck -check-prefix=REMARKS_MISSED %s // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -inline -sil-remarks-missed=sil-inliner -o /dev/null 2>&1 | %FileCheck -check-prefix=REMARKS_MISSED %s
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -inline -save-optimization-record-path %t.yaml -o /dev/null 2>&1 | %FileCheck -allow-empty -check-prefix=NO_REMARKS %s
// RUN: %FileCheck -check-prefix=YAML %s < %t.yaml
// REMARKS_PASSED-NOT: remark: // REMARKS_PASSED-NOT: remark:
// REMARKS_MISSED-NOT: remark: // REMARKS_MISSED-NOT: remark:
// NO_REMARKS-NOT: remark:
sil_stage canonical sil_stage canonical
@@ -190,7 +193,33 @@ bb0:
%c30 = builtin "assert_configuration"() : $Builtin.Int32 %c30 = builtin "assert_configuration"() : $Builtin.Int32
%f = function_ref @update_global: $@convention(thin) () -> () %f = function_ref @update_global: $@convention(thin) () -> ()
// REMARKS_PASSED: inliner_coldblocks.sil:194:3: remark: update_global inlined into regular_large_callee (cost = {{.*}}, benefit = {{.*}}) // REMARKS_PASSED: inliner_coldblocks.sil:223:3: remark: update_global inlined into regular_large_callee (cost = {{.*}}, benefit = {{.*}})
// YAML: --- !Passed
// YAML-NEXT: Pass: sil-inliner
// YAML-NEXT: Name: Inlined
// YAML-NEXT: DebugLoc:
// YAML-NEXT: File: {{.*}}inliner_coldblocks.sil
// YAML-NEXT: Line: 223
// YAML-NEXT: Column: 3
// YAML-NEXT: Function: regular_large_callee
// YAML-NEXT: Args:
// YAML-NEXT: - Callee: update_global
// YAML-NEXT: DebugLoc:
// YAML-NEXT: File: {{.*}}inliner_coldblocks.sil
// YAML-NEXT: Line: 20
// YAML-NEXT: Column: 6
// YAML-NEXT: - String: ' inlined into '
// YAML-NEXT: - Caller: regular_large_callee
// YAML-NEXT: DebugLoc:
// YAML-NEXT: File: {{.*}}inliner_coldblocks.sil
// YAML-NEXT: Line: 162
// YAML-NEXT: Column: 6
// YAML-NEXT: - String: ' (cost = '
// YAML-NEXT: - Cost: '{{.*}}'
// YAML-NEXT: - String: ', benefit = '
// YAML-NEXT: - Benefit: '{{.*}}'
// YAML-NEXT: - String: ')'
// YAML-NEXT: ...
apply %f() : $@convention(thin) () -> () apply %f() : $@convention(thin) () -> ()
%r = tuple () %r = tuple ()
@@ -204,7 +233,22 @@ bb0:
sil @dont_inline_regular_large_callee : $@convention(thin) () -> () { sil @dont_inline_regular_large_callee : $@convention(thin) () -> () {
bb0: bb0:
%f = function_ref @regular_large_callee : $@convention(thin) () -> () %f = function_ref @regular_large_callee : $@convention(thin) () -> ()
// REMARKS_MISSED: inliner_coldblocks.sil:208:8: remark: Not profitable to inline (cost = {{.*}}, benefit = {{.*}}) // REMARKS_MISSED: inliner_coldblocks.sil:252:8: remark: Not profitable to inline (cost = {{.*}}, benefit = {{.*}})
// YAML: --- !Missed
// YAML-NEXT: Pass: sil-inliner
// YAML-NEXT: Name: NoInlinedCost
// YAML-NEXT: DebugLoc:
// YAML-NEXT: File: {{.*}}inliner_coldblocks.sil
// YAML-NEXT: Line: 252
// YAML-NEXT: Column: 8
// YAML-NEXT: Function: dont_inline_regular_large_callee
// YAML-NEXT: Args:
// YAML-NEXT: - String: 'Not profitable to inline (cost = '
// YAML-NEXT: - Cost: '{{.*}}'
// YAML-NEXT: - String: ', benefit = '
// YAML-NEXT: - Benefit: '{{.*}}'
// YAML-NEXT: - String: ')'
// YAML-NEXT: ...
%a = apply %f() : $@convention(thin) () -> () %a = apply %f() : $@convention(thin) () -> ()
%r = tuple () %r = tuple ()
return %r : $() return %r : $()

View File

@@ -40,6 +40,7 @@
#include "llvm/Support/Path.h" #include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h" #include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetSelect.h"
#include "llvm/Support/YAMLTraits.h"
#include <cstdio> #include <cstdio>
using namespace swift; using namespace swift;
@@ -230,6 +231,11 @@ static cl::opt<std::string> PassRemarksMissed(
"the given regular expression"), "the given regular expression"),
cl::Hidden); cl::Hidden);
static cl::opt<std::string>
RemarksFilename("save-optimization-record-path",
cl::desc("YAML output filename for pass remarks"),
cl::value_desc("filename"));
static void runCommandLineSelectedPasses(SILModule *Module, static void runCommandLineSelectedPasses(SILModule *Module,
irgen::IRGenModule *IRGenMod) { irgen::IRGenModule *IRGenMod) {
SILPassManager PM(Module, IRGenMod); SILPassManager PM(Module, IRGenMod);
@@ -419,6 +425,21 @@ int main(int argc, char **argv) {
if (CI.getSILModule()) if (CI.getSILModule())
CI.getSILModule()->setSerializeSILAction([]{}); CI.getSILModule()->setSerializeSILAction([]{});
std::unique_ptr<llvm::raw_fd_ostream> OptRecordFile;
if (RemarksFilename != "") {
std::error_code EC;
OptRecordFile = llvm::make_unique<llvm::raw_fd_ostream>(
RemarksFilename, EC, llvm::sys::fs::F_None);
if (EC) {
llvm::errs() << EC.message() << '\n';
return 1;
}
CI.getSILModule()->setOptRecordStream(
llvm::make_unique<llvm::yaml::Output>(*OptRecordFile,
&CI.getSourceMgr()),
std::move(OptRecordFile));
}
if (OptimizationGroup == OptGroup::Diagnostics) { if (OptimizationGroup == OptGroup::Diagnostics) {
runSILDiagnosticPasses(*CI.getSILModule()); runSILDiagnosticPasses(*CI.getSILModule());
} else if (OptimizationGroup == OptGroup::Performance) { } else if (OptimizationGroup == OptGroup::Performance) {