blob: 838ddc64fe07159767d831f0506c6e8518311306 [file] [log] [blame]
//===--- OptimizationRemark.cpp - Optimization diagnostics ------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
/// \file
/// This file defines the remark type and the emitter class that passes can use
/// to emit optimization diagnostics.
//
//===----------------------------------------------------------------------===//
#include "swift/SIL/OptimizationRemark.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/Demangling/Demangler.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;
using namespace OptRemark;
Argument::Argument(StringRef Key, int N) : Key(Key), Val(llvm::itostr(N)) {}
Argument::Argument(StringRef Key, long N) : Key(Key), Val(llvm::itostr(N)) {}
Argument::Argument(StringRef Key, long long N)
: Key(Key), Val(llvm::itostr(N)) {}
Argument::Argument(StringRef Key, unsigned N)
: Key(Key), Val(llvm::utostr(N)) {}
Argument::Argument(StringRef Key, unsigned long N)
: Key(Key), Val(llvm::utostr(N)) {}
Argument::Argument(StringRef Key, unsigned long long N)
: Key(Key), Val(llvm::utostr(N)) {}
Argument::Argument(StringRef Key, SILFunction *F)
: Key(Key) {
auto DO = Demangle::DemangleOptions::SimplifiedUIDemangleOptions();
// Enable module names so that we have a way of filtering out
// stdlib-related remarks.
DO.DisplayModuleNames = true;
Val = (Twine("\"") + Demangle::demangleSymbolAsString(F->getName(), DO) +
"\"")
.str();
if (F->hasLocation())
Loc = F->getLocation().getSourceLoc();
}
Argument::Argument(StringRef Key, SILType Ty) : Key(Key) {
llvm::raw_string_ostream OS(Val);
Ty.print(OS);
}
Argument::Argument(StringRef Key, CanType Ty) : Key(Key) {
llvm::raw_string_ostream OS(Val);
Ty.print(OS);
}
template <typename DerivedT> std::string Remark<DerivedT>::getMsg() const {
std::string Str;
llvm::raw_string_ostream OS(Str);
for (const Argument &Arg : Args)
OS << Arg.Val;
return OS.str();
}
template <typename DerivedT> std::string Remark<DerivedT>::getDebugMsg() const {
std::string Str;
llvm::raw_string_ostream OS(Str);
if (IndentDebugWidth)
OS << std::string(" ", IndentDebugWidth);
for (const Argument &Arg : Args)
OS << Arg.Val;
OS << "\n";
return OS.str();
}
Emitter::Emitter(StringRef PassName, SILModule &M)
: Module(M), PassName(PassName),
PassedEnabled(
M.getASTContext().LangOpts.OptimizationRemarkPassedPattern &&
M.getASTContext().LangOpts.OptimizationRemarkPassedPattern->match(
PassName)),
MissedEnabled(
M.getASTContext().LangOpts.OptimizationRemarkMissedPattern &&
M.getASTContext().LangOpts.OptimizationRemarkMissedPattern->match(
PassName)) {}
template <typename RemarkT, typename... ArgTypes>
static void emitRemark(SILModule &Module, const Remark<RemarkT> &R,
Diag<ArgTypes...> ID, bool DiagEnabled) {
if (R.getLocation().isInvalid())
return;
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) {
emitRemark(Module, R, diag::opt_remark_passed, isEnabled<RemarkPassed>());
}
void Emitter::emit(const RemarkMissed &R) {
emitRemark(Module, R, diag::opt_remark_missed, isEnabled<RemarkMissed>());
}
void Emitter::emitDebug(const RemarkPassed &R) {
llvm::dbgs() << R.getDebugMsg();
}
void Emitter::emitDebug(const RemarkMissed &R) {
llvm::dbgs() << R.getDebugMsg();
}
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);
std::string Id = (Twine("sil.") + R.getIdentifier()).str();
io.mapRequired("Name", Id);
SourceLoc Loc = R.getLocation();
if (!io.outputting() || Loc.isValid())
io.mapOptional("DebugLoc", Loc);
std::string FN = Demangle::demangleSymbolAsString(
R.getFunction()->getName(),
Demangle::DemangleOptions::SimplifiedUIDemangleOptions());
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());
StringRef File = SM->getDisplayNameForLoc(Loc);
unsigned Line, Col;
std::tie(Line, Col) = SM->getLineAndColumn(Loc);
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)