mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 04:26:07 +00:00
Add support for optimization reports.
Summary: This patch adds a new flag -Rpass=. The flag indicates the name of the optimization pass that should emit remarks stating when it made a transformation to the code. This implements the design I proposed in: https://docs.google.com/document/d/1FYUatSjZZO-zmFBxjOiuOzAy9mhHA8hqdvklZv68WuQ/edit?usp=sharing Other changes: - Add DiagnosticIDs::isRemark(). Use it in printDiagnosticOptions to print "-R" instead of "-W" in the diagnostic message. - In BackendConsumer::OptimizationRemarkHandler, get a SourceLocation object out of the file name, line and column number. Use that location in the call to Diags.Report(). - When -Rpass is used without debug info a note is emitted alerting the user that they need to use -gline-tables-only -gcolumn-info to get this information. CC: llvm-commits Differential Revision: http://llvm-reviews.chandlerc.com/D3226 llvm-svn: 206401
This commit is contained in:
parent
df655013a9
commit
829b170048
@ -102,6 +102,7 @@ class DefaultWarnNoWerror {
|
||||
class DefaultWarnShowInSystemHeader {
|
||||
bit WarningShowInSystemHeader = 1;
|
||||
}
|
||||
class DefaultRemark { DiagMapping DefaultMapping = MAP_REMARK; }
|
||||
|
||||
// Definitions for Diagnostics.
|
||||
include "DiagnosticASTKinds.td"
|
||||
|
@ -114,6 +114,8 @@ def err_drv_unknown_objc_runtime : Error<
|
||||
"unknown or ill-formed Objective-C runtime '%0'">;
|
||||
def err_drv_emit_llvm_link : Error<
|
||||
"-emit-llvm cannot be used when linking">;
|
||||
def err_drv_optimization_remark_pattern : Error<
|
||||
"%0 in '%1'">;
|
||||
|
||||
def warn_O4_is_O3 : Warning<"-O4 is equivalent to -O3">, InGroup<Deprecated>;
|
||||
def warn_drv_optimization_value : Warning<"optimization level '%0' is unsupported; using '%1%2' instead">,
|
||||
|
@ -32,6 +32,12 @@ def err_fe_backend_plugin: Error<"%0">, CatBackend;
|
||||
def remark_fe_backend_plugin: Remark<"%0">, CatBackend, InGroup<RemarkBackendPlugin>;
|
||||
def note_fe_backend_plugin: Note<"%0">, CatBackend;
|
||||
|
||||
def remark_fe_backend_optimization_remark : Remark<"%0">, CatBackend,
|
||||
InGroup<BackendOptimizationRemark>, DefaultRemark;
|
||||
def note_fe_backend_optimization_remark_missing_loc : Note<"use "
|
||||
"-gline-tables-only -gcolumn-info to track source location information "
|
||||
"for this optimization remark">;
|
||||
|
||||
def err_fe_invalid_code_complete_file : Error<
|
||||
"cannot locate code-completion file %0">, DefaultFatal;
|
||||
def err_fe_stdout_binary : Error<"unable to change standard output to binary">,
|
||||
|
@ -665,6 +665,7 @@ def BackendInlineAsm : DiagGroup<"inline-asm">;
|
||||
def BackendFrameLargerThan : DiagGroup<"frame-larger-than">;
|
||||
def BackendPlugin : DiagGroup<"backend-plugin">;
|
||||
def RemarkBackendPlugin : DiagGroup<"remark-backend-plugin">;
|
||||
def BackendOptimizationRemark : DiagGroup<"pass">;
|
||||
|
||||
// Instrumentation based profiling warnings.
|
||||
def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">;
|
||||
|
@ -154,6 +154,9 @@ public:
|
||||
/// default.
|
||||
static bool isDefaultMappingAsError(unsigned DiagID);
|
||||
|
||||
/// \brief Return true if the specified diagnostic is a Remark.
|
||||
static bool isRemark(unsigned DiagID);
|
||||
|
||||
/// \brief Determine whether the given built-in diagnostic ID is a Note.
|
||||
static bool isBuiltinNote(unsigned DiagID);
|
||||
|
||||
|
@ -60,6 +60,7 @@ def I_Group : OptionGroup<"<I group>">, Group<CompileOnly_Group>;
|
||||
def M_Group : OptionGroup<"<M group>">, Group<CompileOnly_Group>;
|
||||
def T_Group : OptionGroup<"<T group>">;
|
||||
def O_Group : OptionGroup<"<O group>">, Group<CompileOnly_Group>;
|
||||
def R_Group : OptionGroup<"<R group>">, Group<CompileOnly_Group>;
|
||||
def W_Group : OptionGroup<"<W group>">, Group<CompileOnly_Group>;
|
||||
def d_Group : OptionGroup<"<d group>">;
|
||||
def f_Group : OptionGroup<"<f group>">, Group<CompileOnly_Group>;
|
||||
@ -253,7 +254,9 @@ def Qn : Flag<["-"], "Qn">;
|
||||
def Qunused_arguments : Flag<["-"], "Qunused-arguments">, Flags<[DriverOption, CoreOption]>,
|
||||
HelpText<"Don't emit warning for unused driver arguments">;
|
||||
def Q : Flag<["-"], "Q">;
|
||||
def R : Flag<["-"], "R">;
|
||||
def Rpass_EQ : Joined<["-"], "Rpass=">, Group<R_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Report transformations performed by optimization passes whose "
|
||||
"name matches the given POSIX regular expression">;
|
||||
def S : Flag<["-"], "S">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
|
||||
HelpText<"Only run preprocess and compilation steps">;
|
||||
def Tbss : JoinedOrSeparate<["-"], "Tbss">, Group<T_Group>;
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "llvm/Support/Regex.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
@ -145,6 +146,13 @@ public:
|
||||
/// Name of the profile file to use as input for -fprofile-instr-use
|
||||
std::string InstrProfileInput;
|
||||
|
||||
/// Regular expression to select optimizations for which we should enable
|
||||
/// optimization remarks. Transformation passes whose name matches this
|
||||
/// expression (and support this feature), will emit a diagnostic
|
||||
/// whenever they perform a transformation. This is enabled by the
|
||||
/// -Rpass=regexp flag.
|
||||
std::shared_ptr<llvm::Regex> OptimizationRemarkPattern;
|
||||
|
||||
public:
|
||||
// Define accessors/mutators for code generation options of enumeration type.
|
||||
#define CODEGENOPT(Name, Bits, Default)
|
||||
|
@ -361,6 +361,11 @@ bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
|
||||
return GetDefaultDiagMappingInfo(DiagID).getMapping() == diag::MAP_ERROR;
|
||||
}
|
||||
|
||||
bool DiagnosticIDs::isRemark(unsigned DiagID) {
|
||||
return DiagID < diag::DIAG_UPPER_LIMIT &&
|
||||
getBuiltinDiagClass(DiagID) == CLASS_REMARK;
|
||||
}
|
||||
|
||||
/// getDescription - Given a diagnostic ID, return a description of the
|
||||
/// issue.
|
||||
StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/DiagnosticInfo.h"
|
||||
#include "llvm/IR/DiagnosticPrinter.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
@ -220,6 +221,11 @@ namespace clang {
|
||||
/// \return True if the diagnostic has been successfully reported, false
|
||||
/// otherwise.
|
||||
bool StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D);
|
||||
/// \brief Specialized handler for the optimization diagnostic.
|
||||
/// Note that this handler only accepts remarks and it always handles
|
||||
/// them.
|
||||
void
|
||||
OptimizationRemarkHandler(const llvm::DiagnosticInfoOptimizationRemark &D);
|
||||
};
|
||||
|
||||
void BackendConsumer::anchor() {}
|
||||
@ -374,6 +380,44 @@ BackendConsumer::StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void BackendConsumer::OptimizationRemarkHandler(
|
||||
const llvm::DiagnosticInfoOptimizationRemark &D) {
|
||||
// We only support remarks.
|
||||
assert (D.getSeverity() == llvm::DS_Remark);
|
||||
|
||||
// Optimization remarks are active only if -Rpass=regexp is given and the
|
||||
// regular expression pattern in 'regexp' matches the name of the pass
|
||||
// name in \p D.
|
||||
if (CodeGenOpts.OptimizationRemarkPattern &&
|
||||
CodeGenOpts.OptimizationRemarkPattern->match(D.getPassName())) {
|
||||
SourceManager &SourceMgr = Context->getSourceManager();
|
||||
FileManager &FileMgr = SourceMgr.getFileManager();
|
||||
StringRef Filename;
|
||||
unsigned Line, Column;
|
||||
D.getLocation(&Filename, &Line, &Column);
|
||||
SourceLocation Loc;
|
||||
if (Line > 0) {
|
||||
// If -gcolumn-info was not used, Column will be 0. This upsets the
|
||||
// source manager, so if Column is not set, set it to 1.
|
||||
if (Column == 0)
|
||||
Column = 1;
|
||||
Loc = SourceMgr.translateFileLineCol(FileMgr.getFile(Filename), Line,
|
||||
Column);
|
||||
}
|
||||
Diags.Report(Loc, diag::remark_fe_backend_optimization_remark)
|
||||
<< D.getMsg().str();
|
||||
|
||||
if (Line == 0)
|
||||
// If we could not extract a source location for the diagnostic,
|
||||
// inform the user how they can get source locations back.
|
||||
//
|
||||
// FIXME: We should really be generating !srcloc annotations when
|
||||
// -Rpass is used. !srcloc annotations need to be emitted in
|
||||
// approximately the same spots as !dbg nodes.
|
||||
Diags.Report(diag::note_fe_backend_optimization_remark_missing_loc);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief This function is invoked when the backend needs
|
||||
/// to report something to the user.
|
||||
void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) {
|
||||
@ -391,6 +435,11 @@ void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) {
|
||||
return;
|
||||
ComputeDiagID(Severity, backend_frame_larger_than, DiagID);
|
||||
break;
|
||||
case llvm::DK_OptimizationRemark:
|
||||
// Optimization remarks are always handled completely by this
|
||||
// handler. There is no generic way of emitting them.
|
||||
OptimizationRemarkHandler(cast<DiagnosticInfoOptimizationRemark>(DI));
|
||||
return;
|
||||
default:
|
||||
// Plugin IDs are not bound to any value as they are set dynamically.
|
||||
ComputeDiagRemarkID(Severity, backend_plugin, DiagID);
|
||||
|
@ -3417,6 +3417,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
A->render(Args, CmdArgs);
|
||||
}
|
||||
|
||||
if (Arg *A = Args.getLastArg(options::OPT_Rpass_EQ))
|
||||
A->render(Args, CmdArgs);
|
||||
|
||||
if (Args.hasArg(options::OPT_mkernel)) {
|
||||
if (!Args.hasArg(options::OPT_fapple_kext) && types::isCXX(InputType))
|
||||
CmdArgs.push_back("-fapple-kext");
|
||||
|
@ -520,6 +520,17 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
|
||||
|
||||
Opts.DependentLibraries = Args.getAllArgValues(OPT_dependent_lib);
|
||||
|
||||
if (Arg *A = Args.getLastArg(OPT_Rpass_EQ)) {
|
||||
StringRef Val = A->getValue();
|
||||
std::string RegexError;
|
||||
Opts.OptimizationRemarkPattern = std::make_shared<llvm::Regex>(Val);
|
||||
if (!Opts.OptimizationRemarkPattern->isValid(RegexError)) {
|
||||
Diags.Report(diag::err_drv_optimization_remark_pattern)
|
||||
<< RegexError << A->getAsString(Args);
|
||||
Opts.OptimizationRemarkPattern.reset();
|
||||
}
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,8 @@ static void printDiagnosticOptions(raw_ostream &OS,
|
||||
|
||||
StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
|
||||
if (!Opt.empty()) {
|
||||
OS << (Started ? "," : " [") << "-W" << Opt;
|
||||
OS << (Started ? "," : " [")
|
||||
<< (DiagnosticIDs::isRemark(Info.getID()) ? "-R" : "-W") << Opt;
|
||||
Started = true;
|
||||
}
|
||||
}
|
||||
|
19
clang/test/Frontend/optimization-remark.c
Normal file
19
clang/test/Frontend/optimization-remark.c
Normal file
@ -0,0 +1,19 @@
|
||||
// This file tests the -Rpass= flag with the inliner. The test is
|
||||
// designed to always trigger the inliner, so it should be independent
|
||||
// of the optimization level.
|
||||
|
||||
// RUN: %clang -c %s -Rpass=inline -O0 -gline-tables-only -o /dev/null 2> %t.err
|
||||
// RUN: FileCheck < %t.err %s --check-prefix=INLINE
|
||||
|
||||
// RUN: %clang -c %s -Rpass=inline -O0 -o /dev/null 2> %t.err
|
||||
// RUN: FileCheck < %t.err %s --check-prefix=INLINE-NO-LOC
|
||||
|
||||
int foo(int x, int y) __attribute__((always_inline));
|
||||
|
||||
int foo(int x, int y) { return x + y; }
|
||||
int bar(int j) { return foo(j, j - 2); }
|
||||
|
||||
// INLINE: remark: foo inlined into bar [-Rpass]
|
||||
|
||||
// INLINE-NO-LOC: {{^remark: foo inlined into bar}}
|
||||
// INLINE-NO-LOC: note: use -gline-tables-only -gcolumn-info to track
|
Loading…
x
Reference in New Issue
Block a user