mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #12585 from anemet/save-opt-record
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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", "")
|
||||||
|
|||||||
@@ -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]>,
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -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) &&
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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.");
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
43
test/Driver/opt-record.swift
Normal file
43
test/Driver/opt-record.swift
Normal 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()
|
||||||
|
}
|
||||||
@@ -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 : $()
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user