blob: d19d9239a3cf4fec6799fc75a91647a22ef2e32a [file] [log] [blame]
//===--- 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, 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);
};
/// Shorthand to insert named-value pairs.
using NV = Argument;
/// 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 <typename DerivedT> class Remark {
/// Arguments collected via the streaming interface.
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
/// 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;
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<DerivedT *>(this);
}
DerivedT &operator<<(Argument A) {
Args.push_back(std::move(A));
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; }
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.
struct RemarkPassed : public Remark<RemarkPassed> {
RemarkPassed(StringRef Id, SILInstruction &I) : Remark(Id, I) {}
};
/// Remark to report a unsuccessful optimization.
struct RemarkMissed : public Remark<RemarkMissed> {
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;
void emit(const RemarkPassed &R);
void emit(const RemarkMissed &R);
template <typename RemarkT> 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 <typename T>
void emit(T RemarkBuilder, decltype(RemarkBuilder()) * = nullptr) {
using RemarkT = decltype(RemarkBuilder());
// Avoid building the remark unless remarks are enabled.
if (isEnabled<RemarkT>() || Module.getOptRecordStream()) {
auto R = RemarkBuilder();
R.setPassName(PassName);
emit(R);
}
}
};
template <> inline bool Emitter::isEnabled<RemarkMissed>() {
return MissedEnabled;
}
template <> inline bool Emitter::isEnabled<RemarkPassed>() {
return PassedEnabled;
}
} // namespace OptRemark
} // namespace swift
#endif