//===--- OptimizationRemark.h - 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. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SIL_OPTIMIZATIONREMARKEMITTER_H #define SWIFT_SIL_OPTIMIZATIONREMARKEMITTER_H #include "swift/Basic/SourceLoc.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" #include "llvm/ADT/StringRef.h" namespace swift { class SILFunction; namespace OptRemark { /// \brief Used in the streaming interface as the general argument type. It /// internally converts everything into a key-value pair. struct Argument { std::string Key; std::string Val; /// If set, the debug location corresponding to the value. SourceLoc Loc; explicit Argument(StringRef Str = "") : Key("String"), Val(Str) {} Argument(StringRef Key, StringRef Val) : Key(Key), Val(Val) {} Argument(StringRef Key, int N); Argument(StringRef Key, long N); Argument(StringRef Key, long long N); Argument(StringRef Key, unsigned N); Argument(StringRef Key, unsigned long N); Argument(StringRef Key, unsigned long long N); Argument(StringRef Key, SILFunction *F); Argument(StringRef Key, SILType *Ty); }; /// Shorthand to insert named-value pairs. using NV = Argument; /// Inserting this into a Remark indents the text when printed as a debug /// message. struct IndentDebug { explicit IndentDebug(unsigned Width) : Width(Width) {} unsigned Width; }; /// The base class for remarks. This can be created by optimization passed to /// report successful and unsuccessful optimizations. CRTP is used to preserve /// the underlying type encoding the remark kind in the insertion operator. template class Remark { /// Arguments collected via the streaming interface. SmallVector Args; /// The name of the pass generating the remark. StringRef PassName; /// Textual identifier for the remark (single-word, camel-case). Can be used /// by external tools reading the YAML output file for optimization remarks to /// identify the remark. StringRef Identifier; /// Source location for the diagnostics. SourceLoc Location; /// The function for the diagnostics. SILFunction *Function; /// Indentation used if this remarks is printed as a debug message. unsigned IndentDebugWidth = 0; protected: Remark(StringRef Identifier, SILInstruction &I) : Identifier(Identifier), Location(I.getLoc().getSourceLoc()), Function(I.getParent()->getParent()) {} public: DerivedT &operator<<(StringRef S) { Args.emplace_back(S); return *static_cast(this); } DerivedT &operator<<(Argument A) { Args.push_back(std::move(A)); return *static_cast(this); } DerivedT &operator<<(IndentDebug ID) { IndentDebugWidth = ID.Width; return *static_cast(this); } StringRef getPassName() const { return PassName; } StringRef getIdentifier() const { return Identifier; } SILFunction *getFunction() const { return Function; } SourceLoc getLocation() const { return Location; } std::string getMsg() const; std::string getDebugMsg() const; Remark &getRemark() { return *this; } SmallVector &getArgs() { return Args; } void setPassName(StringRef PN) { PassName = PN; } }; /// Remark to report a successful optimization. struct RemarkPassed : public Remark { RemarkPassed(StringRef Id, SILInstruction &I) : Remark(Id, I) {} }; /// Remark to report a unsuccessful optimization. struct RemarkMissed : public Remark { RemarkMissed(StringRef Id, SILInstruction &I) : Remark(Id, I) {} }; /// Used to emit the remarks. Passes reporting remarks should create an /// instance of this. class Emitter { SILModule &Module; std::string PassName; bool PassedEnabled; bool MissedEnabled; // Making these non-generic allows out-of-line definition. void emit(const RemarkPassed &R); void emit(const RemarkMissed &R); static void emitDebug(const RemarkPassed &R); static void emitDebug(const RemarkMissed &R); template bool isEnabled(); public: Emitter(StringRef PassName, SILModule &M); /// \brief Take a lambda that returns a remark which will be emitted. The /// lambda is not evaluated unless remarks are enabled. Second argument is /// only used to restrict this to functions. template void emit(T RemarkBuilder, decltype(RemarkBuilder()) * = nullptr) { using RemarkT = decltype(RemarkBuilder()); // Avoid building the remark unless remarks are enabled. if (isEnabled() || Module.getOptRecordStream()) { auto R = RemarkBuilder(); R.setPassName(PassName); emit(R); } } /// Emit an optimization remark or debug message. template static void emitOrDebug(const char *PassName, Emitter *ORE, T RemarkBuilder, decltype(RemarkBuilder()) * = nullptr) { using RemarkT = decltype(RemarkBuilder()); // Avoid building the remark unless remarks are enabled. bool EmitRemark = ORE && (ORE->isEnabled() || ORE->Module.getOptRecordStream()); // Same for DEBUG. bool EmitDebug = false; #ifndef NDEBUG EmitDebug |= llvm::DebugFlag && llvm::isCurrentDebugType(PassName); #endif // NDEBUG if (EmitRemark || EmitDebug) { auto R = RemarkBuilder(); if (EmitDebug) emitDebug(R); if (EmitRemark) { // If we have ORE use the PassName that was set up with ORE. DEBUG_TYPE // may be different if a pass is calling other modules. R.setPassName(ORE->PassName); ORE->emit(R); } } } }; #define REMARK_OR_DEBUG(...) \ OptRemark::Emitter::emitOrDebug(DEBUG_TYPE, __VA_ARGS__) template <> inline bool Emitter::isEnabled() { return MissedEnabled; } template <> inline bool Emitter::isEnabled() { return PassedEnabled; } } // namespace OptRemark } // namespace swift #endif