15ffd83dbSDimitry Andric //===- llvm/IR/LLVMRemarkStreamer.cpp - Remark Streamer -*- C++ ---------*-===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric //
95ffd83dbSDimitry Andric // This file contains the implementation of the conversion between IR
105ffd83dbSDimitry Andric // Diagnostics and serializable remarks::Remark objects.
115ffd83dbSDimitry Andric //
125ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
135ffd83dbSDimitry Andric
145ffd83dbSDimitry Andric #include "llvm/IR/LLVMRemarkStreamer.h"
155ffd83dbSDimitry Andric #include "llvm/IR/DiagnosticInfo.h"
165ffd83dbSDimitry Andric #include "llvm/IR/Function.h"
175ffd83dbSDimitry Andric #include "llvm/IR/GlobalValue.h"
181fd87a68SDimitry Andric #include "llvm/Remarks/RemarkStreamer.h"
195ffd83dbSDimitry Andric #include "llvm/Support/FileSystem.h"
201fd87a68SDimitry Andric #include "llvm/Support/ToolOutputFile.h"
21bdd1243dSDimitry Andric #include <optional>
225ffd83dbSDimitry Andric
235ffd83dbSDimitry Andric using namespace llvm;
245ffd83dbSDimitry Andric
255ffd83dbSDimitry Andric /// DiagnosticKind -> remarks::Type
toRemarkType(enum DiagnosticKind Kind)265ffd83dbSDimitry Andric static remarks::Type toRemarkType(enum DiagnosticKind Kind) {
275ffd83dbSDimitry Andric switch (Kind) {
285ffd83dbSDimitry Andric default:
295ffd83dbSDimitry Andric return remarks::Type::Unknown;
305ffd83dbSDimitry Andric case DK_OptimizationRemark:
315ffd83dbSDimitry Andric case DK_MachineOptimizationRemark:
325ffd83dbSDimitry Andric return remarks::Type::Passed;
335ffd83dbSDimitry Andric case DK_OptimizationRemarkMissed:
345ffd83dbSDimitry Andric case DK_MachineOptimizationRemarkMissed:
355ffd83dbSDimitry Andric return remarks::Type::Missed;
365ffd83dbSDimitry Andric case DK_OptimizationRemarkAnalysis:
375ffd83dbSDimitry Andric case DK_MachineOptimizationRemarkAnalysis:
385ffd83dbSDimitry Andric return remarks::Type::Analysis;
395ffd83dbSDimitry Andric case DK_OptimizationRemarkAnalysisFPCommute:
405ffd83dbSDimitry Andric return remarks::Type::AnalysisFPCommute;
415ffd83dbSDimitry Andric case DK_OptimizationRemarkAnalysisAliasing:
425ffd83dbSDimitry Andric return remarks::Type::AnalysisAliasing;
435ffd83dbSDimitry Andric case DK_OptimizationFailure:
445ffd83dbSDimitry Andric return remarks::Type::Failure;
455ffd83dbSDimitry Andric }
465ffd83dbSDimitry Andric }
475ffd83dbSDimitry Andric
485ffd83dbSDimitry Andric /// DiagnosticLocation -> remarks::RemarkLocation.
49bdd1243dSDimitry Andric static std::optional<remarks::RemarkLocation>
toRemarkLocation(const DiagnosticLocation & DL)505ffd83dbSDimitry Andric toRemarkLocation(const DiagnosticLocation &DL) {
515ffd83dbSDimitry Andric if (!DL.isValid())
52bdd1243dSDimitry Andric return std::nullopt;
535ffd83dbSDimitry Andric StringRef File = DL.getRelativePath();
545ffd83dbSDimitry Andric unsigned Line = DL.getLine();
555ffd83dbSDimitry Andric unsigned Col = DL.getColumn();
565ffd83dbSDimitry Andric return remarks::RemarkLocation{File, Line, Col};
575ffd83dbSDimitry Andric }
585ffd83dbSDimitry Andric
595ffd83dbSDimitry Andric /// LLVM Diagnostic -> Remark
605ffd83dbSDimitry Andric remarks::Remark
toRemark(const DiagnosticInfoOptimizationBase & Diag) const615ffd83dbSDimitry Andric LLVMRemarkStreamer::toRemark(const DiagnosticInfoOptimizationBase &Diag) const {
625ffd83dbSDimitry Andric remarks::Remark R; // The result.
635ffd83dbSDimitry Andric R.RemarkType = toRemarkType(static_cast<DiagnosticKind>(Diag.getKind()));
645ffd83dbSDimitry Andric R.PassName = Diag.getPassName();
655ffd83dbSDimitry Andric R.RemarkName = Diag.getRemarkName();
665ffd83dbSDimitry Andric R.FunctionName =
675ffd83dbSDimitry Andric GlobalValue::dropLLVMManglingEscape(Diag.getFunction().getName());
685ffd83dbSDimitry Andric R.Loc = toRemarkLocation(Diag.getLocation());
695ffd83dbSDimitry Andric R.Hotness = Diag.getHotness();
705ffd83dbSDimitry Andric
715ffd83dbSDimitry Andric for (const DiagnosticInfoOptimizationBase::Argument &Arg : Diag.getArgs()) {
725ffd83dbSDimitry Andric R.Args.emplace_back();
735ffd83dbSDimitry Andric R.Args.back().Key = Arg.Key;
745ffd83dbSDimitry Andric R.Args.back().Val = Arg.Val;
755ffd83dbSDimitry Andric R.Args.back().Loc = toRemarkLocation(Arg.Loc);
765ffd83dbSDimitry Andric }
775ffd83dbSDimitry Andric
785ffd83dbSDimitry Andric return R;
795ffd83dbSDimitry Andric }
805ffd83dbSDimitry Andric
emit(const DiagnosticInfoOptimizationBase & Diag)815ffd83dbSDimitry Andric void LLVMRemarkStreamer::emit(const DiagnosticInfoOptimizationBase &Diag) {
825ffd83dbSDimitry Andric if (!RS.matchesFilter(Diag.getPassName()))
835ffd83dbSDimitry Andric return;
845ffd83dbSDimitry Andric
855ffd83dbSDimitry Andric // First, convert the diagnostic to a remark.
865ffd83dbSDimitry Andric remarks::Remark R = toRemark(Diag);
875ffd83dbSDimitry Andric // Then, emit the remark through the serializer.
885ffd83dbSDimitry Andric RS.getSerializer().emit(R);
895ffd83dbSDimitry Andric }
905ffd83dbSDimitry Andric
915ffd83dbSDimitry Andric char LLVMRemarkSetupFileError::ID = 0;
925ffd83dbSDimitry Andric char LLVMRemarkSetupPatternError::ID = 0;
935ffd83dbSDimitry Andric char LLVMRemarkSetupFormatError::ID = 0;
945ffd83dbSDimitry Andric
setupLLVMOptimizationRemarks(LLVMContext & Context,StringRef RemarksFilename,StringRef RemarksPasses,StringRef RemarksFormat,bool RemarksWithHotness,std::optional<uint64_t> RemarksHotnessThreshold)955ffd83dbSDimitry Andric Expected<std::unique_ptr<ToolOutputFile>> llvm::setupLLVMOptimizationRemarks(
965ffd83dbSDimitry Andric LLVMContext &Context, StringRef RemarksFilename, StringRef RemarksPasses,
975ffd83dbSDimitry Andric StringRef RemarksFormat, bool RemarksWithHotness,
98bdd1243dSDimitry Andric std::optional<uint64_t> RemarksHotnessThreshold) {
99*06c3fb27SDimitry Andric if (RemarksWithHotness || RemarksHotnessThreshold.value_or(1))
1005ffd83dbSDimitry Andric Context.setDiagnosticsHotnessRequested(true);
1015ffd83dbSDimitry Andric
1025ffd83dbSDimitry Andric Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold);
1035ffd83dbSDimitry Andric
1045ffd83dbSDimitry Andric if (RemarksFilename.empty())
1055ffd83dbSDimitry Andric return nullptr;
1065ffd83dbSDimitry Andric
1075ffd83dbSDimitry Andric Expected<remarks::Format> Format = remarks::parseFormat(RemarksFormat);
1085ffd83dbSDimitry Andric if (Error E = Format.takeError())
1095ffd83dbSDimitry Andric return make_error<LLVMRemarkSetupFormatError>(std::move(E));
1105ffd83dbSDimitry Andric
1115ffd83dbSDimitry Andric std::error_code EC;
112fe6060f1SDimitry Andric auto Flags = *Format == remarks::Format::YAML ? sys::fs::OF_TextWithCRLF
1135ffd83dbSDimitry Andric : sys::fs::OF_None;
1145ffd83dbSDimitry Andric auto RemarksFile =
1155ffd83dbSDimitry Andric std::make_unique<ToolOutputFile>(RemarksFilename, EC, Flags);
1165ffd83dbSDimitry Andric // We don't use llvm::FileError here because some diagnostics want the file
1175ffd83dbSDimitry Andric // name separately.
1185ffd83dbSDimitry Andric if (EC)
1195ffd83dbSDimitry Andric return make_error<LLVMRemarkSetupFileError>(errorCodeToError(EC));
1205ffd83dbSDimitry Andric
1215ffd83dbSDimitry Andric Expected<std::unique_ptr<remarks::RemarkSerializer>> RemarkSerializer =
1225ffd83dbSDimitry Andric remarks::createRemarkSerializer(
1235ffd83dbSDimitry Andric *Format, remarks::SerializerMode::Separate, RemarksFile->os());
1245ffd83dbSDimitry Andric if (Error E = RemarkSerializer.takeError())
1255ffd83dbSDimitry Andric return make_error<LLVMRemarkSetupFormatError>(std::move(E));
1265ffd83dbSDimitry Andric
1275ffd83dbSDimitry Andric // Create the main remark streamer.
1285ffd83dbSDimitry Andric Context.setMainRemarkStreamer(std::make_unique<remarks::RemarkStreamer>(
1295ffd83dbSDimitry Andric std::move(*RemarkSerializer), RemarksFilename));
1305ffd83dbSDimitry Andric
1315ffd83dbSDimitry Andric // Create LLVM's optimization remarks streamer.
1325ffd83dbSDimitry Andric Context.setLLVMRemarkStreamer(
1335ffd83dbSDimitry Andric std::make_unique<LLVMRemarkStreamer>(*Context.getMainRemarkStreamer()));
1345ffd83dbSDimitry Andric
1355ffd83dbSDimitry Andric if (!RemarksPasses.empty())
1365ffd83dbSDimitry Andric if (Error E = Context.getMainRemarkStreamer()->setFilter(RemarksPasses))
1375ffd83dbSDimitry Andric return make_error<LLVMRemarkSetupPatternError>(std::move(E));
1385ffd83dbSDimitry Andric
1395ffd83dbSDimitry Andric return std::move(RemarksFile);
1405ffd83dbSDimitry Andric }
1415ffd83dbSDimitry Andric
setupLLVMOptimizationRemarks(LLVMContext & Context,raw_ostream & OS,StringRef RemarksPasses,StringRef RemarksFormat,bool RemarksWithHotness,std::optional<uint64_t> RemarksHotnessThreshold)142e8d8bef9SDimitry Andric Error llvm::setupLLVMOptimizationRemarks(
143e8d8bef9SDimitry Andric LLVMContext &Context, raw_ostream &OS, StringRef RemarksPasses,
144e8d8bef9SDimitry Andric StringRef RemarksFormat, bool RemarksWithHotness,
145bdd1243dSDimitry Andric std::optional<uint64_t> RemarksHotnessThreshold) {
146*06c3fb27SDimitry Andric if (RemarksWithHotness || RemarksHotnessThreshold.value_or(1))
1475ffd83dbSDimitry Andric Context.setDiagnosticsHotnessRequested(true);
1485ffd83dbSDimitry Andric
1495ffd83dbSDimitry Andric Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold);
1505ffd83dbSDimitry Andric
1515ffd83dbSDimitry Andric Expected<remarks::Format> Format = remarks::parseFormat(RemarksFormat);
1525ffd83dbSDimitry Andric if (Error E = Format.takeError())
1535ffd83dbSDimitry Andric return make_error<LLVMRemarkSetupFormatError>(std::move(E));
1545ffd83dbSDimitry Andric
1555ffd83dbSDimitry Andric Expected<std::unique_ptr<remarks::RemarkSerializer>> RemarkSerializer =
1565ffd83dbSDimitry Andric remarks::createRemarkSerializer(*Format,
1575ffd83dbSDimitry Andric remarks::SerializerMode::Separate, OS);
1585ffd83dbSDimitry Andric if (Error E = RemarkSerializer.takeError())
1595ffd83dbSDimitry Andric return make_error<LLVMRemarkSetupFormatError>(std::move(E));
1605ffd83dbSDimitry Andric
1615ffd83dbSDimitry Andric // Create the main remark streamer.
1625ffd83dbSDimitry Andric Context.setMainRemarkStreamer(
1635ffd83dbSDimitry Andric std::make_unique<remarks::RemarkStreamer>(std::move(*RemarkSerializer)));
1645ffd83dbSDimitry Andric
1655ffd83dbSDimitry Andric // Create LLVM's optimization remarks streamer.
1665ffd83dbSDimitry Andric Context.setLLVMRemarkStreamer(
1675ffd83dbSDimitry Andric std::make_unique<LLVMRemarkStreamer>(*Context.getMainRemarkStreamer()));
1685ffd83dbSDimitry Andric
1695ffd83dbSDimitry Andric if (!RemarksPasses.empty())
1705ffd83dbSDimitry Andric if (Error E = Context.getMainRemarkStreamer()->setFilter(RemarksPasses))
1715ffd83dbSDimitry Andric return make_error<LLVMRemarkSetupPatternError>(std::move(E));
1725ffd83dbSDimitry Andric
1735ffd83dbSDimitry Andric return Error::success();
1745ffd83dbSDimitry Andric }
175