| //===--- 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) |