[Remarks] Refactor remark diagnostic emission in a RemarkStreamer

This allows us to store more info about where we're emitting the remarks
without cluttering LLVMContext. This is needed for future support for
the remark section.

Differential Revision: https://reviews.llvm.org/D58996

llvm-svn: 355507
This commit is contained in:
Francis Visoiu Mistrih 2019-03-06 14:32:08 +00:00
parent 1bdc2d1874
commit 9052f50cb4
14 changed files with 131 additions and 44 deletions

View File

@ -30,6 +30,7 @@
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/RemarkStreamer.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Linker/Linker.h"
#include "llvm/Pass.h"
@ -276,8 +277,8 @@ namespace clang {
return;
}
Ctx.setDiagnosticsOutputFile(
llvm::make_unique<yaml::Output>(OptRecordFile->os()));
Ctx.setRemarkStreamer(llvm::make_unique<RemarkStreamer>(
CodeGenOpts.OptRecordFile, OptRecordFile->os()));
if (CodeGenOpts.getProfileUse() != CodeGenOptions::ProfileNone)
Ctx.setDiagnosticsHotnessRequested(true);

View File

@ -77,7 +77,7 @@ public:
// remarks enabled. We can't currently check whether remarks are requested
// for the calling pass since that requires actually building the remark.
if (F->getContext().getDiagnosticsOutputFile() ||
if (F->getContext().getRemarkStreamer() ||
F->getContext().getDiagHandlerPtr()->isAnyRemarkEnabled()) {
auto R = RemarkBuilder();
emit((DiagnosticInfoOptimizationBase &)R);
@ -92,7 +92,7 @@ public:
/// provide more context so that non-trivial false positives can be quickly
/// detected by the user.
bool allowExtraAnalysis(StringRef PassName) const {
return (F->getContext().getDiagnosticsOutputFile() ||
return (F->getContext().getRemarkStreamer() ||
F->getContext().getDiagHandlerPtr()->isAnyRemarkEnabled(PassName));
}

View File

@ -158,9 +158,10 @@ public:
/// (1) to filter trivial false positives or (2) to provide more context so
/// that non-trivial false positives can be quickly detected by the user.
bool allowExtraAnalysis(StringRef PassName) const {
return (MF.getFunction().getContext().getDiagnosticsOutputFile() ||
MF.getFunction().getContext()
.getDiagHandlerPtr()->isAnyRemarkEnabled(PassName));
return (
MF.getFunction().getContext().getRemarkStreamer() ||
MF.getFunction().getContext().getDiagHandlerPtr()->isAnyRemarkEnabled(
PassName));
}
/// Take a lambda that returns a remark which will be emitted. Second
@ -171,8 +172,11 @@ public:
// remarks enabled. We can't currently check whether remarks are requested
// for the calling pass since that requires actually building the remark.
if (MF.getFunction().getContext().getDiagnosticsOutputFile() ||
MF.getFunction().getContext().getDiagHandlerPtr()->isAnyRemarkEnabled()) {
if (MF.getFunction().getContext().getRemarkStreamer() ||
MF.getFunction()
.getContext()
.getDiagHandlerPtr()
->isAnyRemarkEnabled()) {
auto R = RemarkBuilder();
emit((DiagnosticInfoOptimizationBase &)R);
}

View File

@ -35,12 +35,8 @@ template <typename T> class SmallVectorImpl;
class SMDiagnostic;
class StringRef;
class Twine;
namespace yaml {
class Output;
} // end namespace yaml
class RemarkStreamer;
class raw_ostream;
namespace SyncScope {
@ -246,16 +242,23 @@ public:
/// included in optimization diagnostics.
void setDiagnosticsHotnessThreshold(uint64_t Threshold);
/// Return the YAML file used by the backend to save optimization
/// diagnostics. If null, diagnostics are not saved in a file but only
/// emitted via the diagnostic handler.
yaml::Output *getDiagnosticsOutputFile();
/// Set the diagnostics output file used for optimization diagnostics.
/// Return the streamer used by the backend to save remark diagnostics. If it
/// does not exist, diagnostics are not saved in a file but only emitted via
/// the diagnostic handler.
RemarkStreamer *getRemarkStreamer();
const RemarkStreamer *getRemarkStreamer() const;
/// Set the diagnostics output used for optimization diagnostics.
/// This filename may be embedded in a section for tools to find the
/// diagnostics whenever they're needed.
///
/// By default or if invoked with null, diagnostics are not saved in a file
/// but only emitted via the diagnostic handler. Even if an output file is
/// set, the handler is invoked for each diagnostic message.
void setDiagnosticsOutputFile(std::unique_ptr<yaml::Output> F);
/// If a remark streamer is already set, it will be replaced with
/// \p RemarkStreamer.
///
/// By default, diagnostics are not saved in a file but only emitted via the
/// diagnostic handler. Even if an output file is set, the handler is invoked
/// for each diagnostic message.
void setRemarkStreamer(std::unique_ptr<RemarkStreamer> RemarkStreamer);
/// Get the prefix that should be printed in front of a diagnostic of
/// the given \p Severity

View File

@ -0,0 +1,44 @@
//===- llvm/IR/RemarkStreamer.h - Remark Streamer ---------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file declares the main interface for outputting remarks.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_IR_REMARKSTREAMER_H
#define LLVM_IR_REMARKSTREAMER_H
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
#include <vector>
namespace llvm {
/// Streamer for remarks.
class RemarkStreamer {
/// The filename that the remark diagnostics are emitted to.
const std::string Filename;
/// The open raw_ostream that the remark diagnostics are emitted to.
raw_ostream &OS;
/// The YAML streamer.
yaml::Output YAMLOutput;
public:
RemarkStreamer(StringRef Filename, raw_ostream& OS);
/// Return the filename that the remark diagnostics are emitted to.
StringRef getFilename() const { return Filename; }
/// Return stream that the remark diagnostics are emitted to.
raw_ostream &getStream() { return OS; }
/// Emit a diagnostic through the streamer.
void emit(const DiagnosticInfoOptimizationBase &Diag);
};
} // end namespace llvm
#endif // LLVM_IR_REMARKSTREAMER_H

View File

@ -78,6 +78,7 @@
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/RemarkStreamer.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/MC/MCAsmInfo.h"

View File

@ -46,6 +46,7 @@ add_llvm_library(LLVMCore
PassManager.cpp
PassRegistry.cpp
PassTimingInfo.cpp
RemarkStreamer.cpp
SafepointIRVerifier.cpp
ProfileSummary.cpp
Statepoint.cpp

View File

@ -27,6 +27,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/RemarkStreamer.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h"

View File

@ -21,6 +21,7 @@
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/RemarkStreamer.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
@ -160,12 +161,15 @@ uint64_t LLVMContext::getDiagnosticsHotnessThreshold() const {
return pImpl->DiagnosticsHotnessThreshold;
}
yaml::Output *LLVMContext::getDiagnosticsOutputFile() {
return pImpl->DiagnosticsOutputFile.get();
RemarkStreamer *LLVMContext::getRemarkStreamer() {
return pImpl->RemarkStreamer.get();
}
void LLVMContext::setDiagnosticsOutputFile(std::unique_ptr<yaml::Output> F) {
pImpl->DiagnosticsOutputFile = std::move(F);
const RemarkStreamer *LLVMContext::getRemarkStreamer() const {
return const_cast<LLVMContext *>(this)->getRemarkStreamer();
}
void LLVMContext::setRemarkStreamer(
std::unique_ptr<RemarkStreamer> RemarkStreamer) {
pImpl->RemarkStreamer = std::move(RemarkStreamer);
}
DiagnosticHandler::DiagnosticHandlerTy
@ -228,14 +232,10 @@ LLVMContext::getDiagnosticMessagePrefix(DiagnosticSeverity Severity) {
}
void LLVMContext::diagnose(const DiagnosticInfo &DI) {
if (auto *OptDiagBase = dyn_cast<DiagnosticInfoOptimizationBase>(&DI)) {
yaml::Output *Out = getDiagnosticsOutputFile();
if (Out) {
// For remarks the << operator takes a reference to a pointer.
auto *P = const_cast<DiagnosticInfoOptimizationBase *>(OptDiagBase);
*Out << P;
}
}
if (auto *OptDiagBase = dyn_cast<DiagnosticInfoOptimizationBase>(&DI))
if (RemarkStreamer *RS = getRemarkStreamer())
RS->emit(*OptDiagBase);
// If there is a report handler, use it.
if (pImpl->DiagHandler &&
(!pImpl->RespectDiagnosticFilters || isDiagnosticEnabled(DI)) &&

View File

@ -37,6 +37,7 @@
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/RemarkStreamer.h"
#include "llvm/IR/TrackingMDRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
@ -1226,7 +1227,7 @@ public:
bool RespectDiagnosticFilters = false;
bool DiagnosticsHotnessRequested = false;
uint64_t DiagnosticsHotnessThreshold = 0;
std::unique_ptr<yaml::Output> DiagnosticsOutputFile;
std::unique_ptr<RemarkStreamer> RemarkStreamer;
LLVMContext::YieldCallbackTy YieldCallback = nullptr;
void *YieldOpaqueHandle = nullptr;

View File

@ -0,0 +1,28 @@
//===- llvm/IR/RemarkStreamer.cpp - Remark Streamer -*- C++ -------------*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains the implementation of the remark outputting as part of
// LLVMContext.
//
//===----------------------------------------------------------------------===//
#include "llvm/IR/RemarkStreamer.h"
using namespace llvm;
RemarkStreamer::RemarkStreamer(StringRef Filename, raw_ostream &OS)
: Filename(Filename), OS(OS),
YAMLOutput(OS, reinterpret_cast<void *>(this)) {
assert(!Filename.empty() && "This needs to be a real filename.");
}
void RemarkStreamer::emit(const DiagnosticInfoOptimizationBase &Diag) {
DiagnosticInfoOptimizationBase *DiagPtr =
const_cast<DiagnosticInfoOptimizationBase *>(&Diag);
YAMLOutput << DiagPtr;
}

View File

@ -24,6 +24,7 @@
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/RemarkStreamer.h"
#include "llvm/LTO/LTOBackend.h"
#include "llvm/LTO/SummaryBasedOptimizations.h"
#include "llvm/Linker/IRMover.h"
@ -1326,8 +1327,8 @@ lto::setupOptimizationRemarks(LLVMContext &Context,
llvm::make_unique<ToolOutputFile>(Filename, EC, sys::fs::F_None);
if (EC)
return errorCodeToError(EC);
Context.setDiagnosticsOutputFile(
llvm::make_unique<yaml::Output>(DiagnosticFile->os()));
Context.setRemarkStreamer(
llvm::make_unique<RemarkStreamer>(Filename, DiagnosticFile->os()));
DiagnosticFile->keep();
return std::move(DiagnosticFile);
}

View File

@ -31,6 +31,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/RemarkStreamer.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/MC/SubtargetFeature.h"
@ -333,8 +334,8 @@ int main(int argc, char **argv) {
WithColor::error(errs(), argv[0]) << EC.message() << '\n';
return 1;
}
Context.setDiagnosticsOutputFile(
llvm::make_unique<yaml::Output>(YamlFile->os()));
Context.setRemarkStreamer(
llvm::make_unique<RemarkStreamer>(RemarksFilename, YamlFile->os()));
}
if (InputLanguage != "" && InputLanguage != "ir" &&

View File

@ -33,6 +33,7 @@
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/LegacyPassNameParser.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/RemarkStreamer.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/InitializePasses.h"
@ -563,8 +564,8 @@ int main(int argc, char **argv) {
errs() << EC.message() << '\n';
return 1;
}
Context.setDiagnosticsOutputFile(
llvm::make_unique<yaml::Output>(OptRemarkFile->os()));
Context.setRemarkStreamer(llvm::make_unique<RemarkStreamer>(
RemarksFilename, OptRemarkFile->os()));
}
// Load the input module...