victorkingi updated this revision to Diff 548941.
victorkingi added a comment.
rebasing
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D156320/new/
https://reviews.llvm.org/D156320
Files:
flang/include/flang/Frontend/CodeGenOptions.h
flang/lib/Frontend/CompilerInvocation.cpp
flang/lib/Frontend/FrontendActions.cpp
flang/lib/Frontend/TextDiagnosticPrinter.cpp
flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
flang/test/Driver/optimization-remark.f90
Index: flang/test/Driver/optimization-remark.f90
===================================================================
--- /dev/null
+++ flang/test/Driver/optimization-remark.f90
@@ -0,0 +1,55 @@
+! This file tests the -Rpass family of flags (-Rpass, -Rpass-missed
+! and -Rpass-analysis)
+! loop-delete isn't enabled at O0 so we use at least O1
+
+! Check that we can override -Rpass= with -Rno-pass.
+! RUN: %flang_fc1 %s -O1 -Rpass=loop-delete -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS
+! RUN: %flang_fc1 %s -O1 -Rpass=loop-delete -Rno-pass -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK-NO-REMARKS
+! RUN: %flang_fc1 %s -O1 -Rpass=loop-delete -Rno-everything -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK-NO-REMARKS
+! RUN: %flang_fc1 %s -O1 -Rpass=loop-delete -Rno-everything -Reverything -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS
+
+! -Reverything implies -Rpass=.*.
+! RUN: %flang_fc1 %s -O1 -Reverything -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS
+
+! -Rpass implies -Rpass=.*
+! RUN: %flang_fc1 %s -O1 -Rpass -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS
+
+! Check error on bad regex
+! RUN: not %flang %s -O1 -Rpass=[ 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS-ERROR
+
+! Check full -Rpass message is emitted
+! RUN: %flang %s -O1 -Rpass=loop-delete 2>&1 | FileCheck %s
+
+! Check full -Rpass-missed message is emitted
+! RUN: %flang %s -O1 -Rpass-missed=loop-vectorize 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS-MISSED
+
+! Check full -Rpass-analysis message is emitted
+! RUN: %flang %s -O1 -Rpass-analysis=loop-vectorize 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS-ANALYSIS
+
+
+! CHECK: remark: Loop deleted because it is invariant
+
+! CHECK-REMARKS-MISSED: remark: loop not vectorized
+! CHECK-REMARKS-ANALYSIS: remark: loop not vectorized: call instruction cannot be vectorized
+! CHECK-REMARKS: remark:
+
+! CHECK-NO-REMARKS-NOT: remark:
+
+! CHECK-REMARKS-ERROR: error: in pattern '-Rpass=[': brackets ([ ]) not balanced
+
+
+program forttest
+ implicit none
+ real, dimension(1:50) :: aR1
+ integer :: n
+
+ do n = 1,50
+ aR1(n) = n * 1.34
+ print *, "hello"
+ end do
+
+ do n = 1,50
+ aR1(n) = n * 1.34
+ end do
+
+end program forttest
Index: flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
===================================================================
--- flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -165,6 +165,10 @@
// Honor color diagnostics.
flang->getDiagnosticOpts().ShowColors = flang->getFrontendOpts().showColors;
+ flang->getDiagnosticOpts().ShowOptionNames = 1;
+
+ clang::ProcessWarningOptions(flang->getDiagnostics(),
+ flang->getDiagnosticOpts(), false);
// Create and execute the frontend action.
std::unique_ptr<FrontendAction> act(createFrontendAction(*flang));
Index: flang/lib/Frontend/TextDiagnosticPrinter.cpp
===================================================================
--- flang/lib/Frontend/TextDiagnosticPrinter.cpp
+++ flang/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -20,6 +20,10 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
+#include <clang/Frontend/TextDiagnosticPrinter.h>
+#include <filesystem>
+#include <string>
+#include <vector>
using namespace Fortran::frontend;
@@ -29,6 +33,28 @@
TextDiagnosticPrinter::~TextDiagnosticPrinter() {}
+// Print any diagnostic option information to a raw_ostream.
+static void printDiagnosticOptions(llvm::raw_ostream &os,
+ clang::DiagnosticsEngine::Level level,
+ const clang::Diagnostic &info,
+ const clang::DiagnosticOptions &diagOpts) {
+ bool started = false;
+ if (diagOpts.ShowOptionNames) {
+ llvm::StringRef opt =
+ clang::DiagnosticIDs::getWarningOptionForDiag(info.getID());
+ if (!opt.empty()) {
+ os << (started ? "," : " [")
+ << (level == clang::DiagnosticsEngine::Remark ? "-R" : "-W") << opt;
+ llvm::StringRef optValue = info.getDiags()->getFlagValue();
+ if (!optValue.empty())
+ os << "=" << optValue;
+ started = true;
+ }
+ }
+ if (started)
+ os << ']';
+}
+
void TextDiagnosticPrinter::HandleDiagnostic(
clang::DiagnosticsEngine::Level level, const clang::Diagnostic &info) {
// Default implementation (Warnings/errors count).
@@ -40,6 +66,7 @@
info.FormatDiagnostic(outStr);
llvm::raw_svector_ostream diagMessageStream(outStr);
+ printDiagnosticOptions(diagMessageStream, level, info, *diagOpts);
if (!prefix.empty())
os << prefix << ": ";
@@ -48,12 +75,46 @@
assert(!info.getLocation().isValid() &&
"Diagnostics with valid source location are not supported");
+ // split incoming string to get the absolute path and filename in the
+ // case we are receiving optimization remarks from StandaloneBackendConsumer
+ std::string s = std::string(diagMessageStream.str());
+ std::string delimiter = ";;";
+
+ size_t pos = 0;
+ std::vector<std::string> tokens;
+ while ((pos = s.find(delimiter)) != std::string::npos) {
+ tokens.push_back(s.substr(0, pos));
+ s.erase(0, pos + delimiter.length());
+ }
+
+ // tokens will always be of size 2 in the case of optimization
+ // remark message received, in this format;
+ // [file location with line and column];;[path to file];;[the remark message]
+ if (tokens.size() == 2) {
+ // extract absolute path from the provided relative path
+ std::filesystem::path absPath(tokens[1]);
+ std::filesystem::path canonicalPath =
+ std::filesystem::weakly_canonical(absPath);
+
+ // we don't need the filename since we will append tokens[0]
+ // which is the filename, line and column number
+ canonicalPath.remove_filename();
+ absPath = canonicalPath.make_preferred().string();
+
+ // used for changing only the bold attribute
+ if (diagOpts->ShowColors)
+ os.changeColor(llvm::raw_ostream::SAVEDCOLOR, true);
+
+ // print absolute path, file name, line and column
+ os << absPath << tokens[0] << ": ";
+ }
+
Fortran::frontend::TextDiagnostic::printDiagnosticLevel(os, level,
diagOpts->ShowColors);
Fortran::frontend::TextDiagnostic::printDiagnosticMessage(
os,
- /*IsSupplemental=*/level == clang::DiagnosticsEngine::Note,
- diagMessageStream.str(), diagOpts->ShowColors);
+ /*IsSupplemental=*/level == clang::DiagnosticsEngine::Note, s,
+ diagOpts->ShowColors);
os.flush();
}
Index: flang/lib/Frontend/FrontendActions.cpp
===================================================================
--- flang/lib/Frontend/FrontendActions.cpp
+++ flang/lib/Frontend/FrontendActions.cpp
@@ -48,6 +48,7 @@
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
+#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/LLVMRemarkStreamer.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Verifier.h"
@@ -923,6 +924,107 @@
mpm.run(*llvmModule, mam);
}
+class StandaloneBackendConsumer : public llvm::DiagnosticHandler {
+
+ const CodeGenOptions &codeGenOpts;
+ clang::DiagnosticsEngine &diags;
+
+public:
+ StandaloneBackendConsumer(clang::DiagnosticsEngine &diags,
+ const CodeGenOptions &codeGenOpts)
+ : codeGenOpts(codeGenOpts), diags(diags) {}
+
+ bool isAnalysisRemarkEnabled(llvm::StringRef passName) const override {
+ return codeGenOpts.OptimizationRemarkAnalysis.patternMatches(passName);
+ }
+ bool isMissedOptRemarkEnabled(llvm::StringRef passName) const override {
+ return codeGenOpts.OptimizationRemarkMissed.patternMatches(passName);
+ }
+ bool isPassedOptRemarkEnabled(llvm::StringRef passName) const override {
+ return codeGenOpts.OptimizationRemark.patternMatches(passName);
+ }
+
+ bool isAnyRemarkEnabled() const override {
+ return codeGenOpts.OptimizationRemarkAnalysis.hasValidPattern() ||
+ codeGenOpts.OptimizationRemarkMissed.hasValidPattern() ||
+ codeGenOpts.OptimizationRemark.hasValidPattern();
+ }
+
+ void emitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase &d,
+ unsigned diagID) {
+ // We only support warnings and remarks.
+ assert(d.getSeverity() == llvm::DS_Remark ||
+ d.getSeverity() == llvm::DS_Warning);
+
+ std::string msg;
+ llvm::raw_string_ostream msgStream(msg);
+
+ if (d.isLocationAvailable()) {
+ // Since sourceMgr isn't available, send file name and absolute path
+ // through msgStream, to use for printing
+ msgStream << d.getLocationStr() << ";;" << d.getAbsolutePath() << ";;";
+ msgStream << d.getMsg();
+ } else {
+ msgStream << d.getMsg();
+ llvm::DiagnosticPrinterRawOStream dp(msgStream);
+ d.print(dp);
+ }
+
+ // Emit message.
+ diags.Report(diagID) << clang::AddFlagValue(d.getPassName())
+ << msgStream.str();
+ }
+
+ void
+ optimizationRemarkHandler(const llvm::DiagnosticInfoOptimizationBase &d) {
+ if (d.isPassed()) {
+ // Optimization remarks are active only if the -Rpass flag has a regular
+ // expression that matches the name of the pass name in \p D.
+ if (codeGenOpts.OptimizationRemark.patternMatches(d.getPassName()))
+ emitOptimizationMessage(
+ d, clang::diag::remark_fe_backend_optimization_remark);
+
+ } else if (d.isMissed()) {
+ // Missed optimization remarks are active only if the -Rpass-missed
+ // flag has a regular expression that matches the name of the pass
+ // name in \p D.
+ if (codeGenOpts.OptimizationRemarkMissed.patternMatches(d.getPassName()))
+ emitOptimizationMessage(
+ d, clang::diag::remark_fe_backend_optimization_remark_missed);
+ } else {
+ assert(d.isAnalysis() && "Unknown remark type");
+
+ bool shouldAlwaysPrint = false;
+ if (auto *ora = llvm::dyn_cast<llvm::OptimizationRemarkAnalysis>(&d))
+ shouldAlwaysPrint = ora->shouldAlwaysPrint();
+
+ if (shouldAlwaysPrint ||
+ codeGenOpts.OptimizationRemarkAnalysis.patternMatches(
+ d.getPassName()))
+ emitOptimizationMessage(
+ d, clang::diag::remark_fe_backend_optimization_remark_analysis);
+ }
+ }
+
+ bool handleDiagnostics(const llvm::DiagnosticInfo &di) override {
+ switch (di.getKind()) {
+ case llvm::DK_OptimizationRemark:
+ optimizationRemarkHandler(llvm::cast<llvm::OptimizationRemark>(di));
+ break;
+ case llvm::DK_OptimizationRemarkMissed:
+ optimizationRemarkHandler(llvm::cast<llvm::OptimizationRemarkMissed>(di));
+ break;
+ case llvm::DK_OptimizationRemarkAnalysis:
+ optimizationRemarkHandler(
+ llvm::cast<llvm::OptimizationRemarkAnalysis>(di));
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+};
+
void CodeGenAction::embedOffloadObjects() {
CompilerInstance &ci = this->getInstance();
const auto &cgOpts = ci.getInvocation().getCodeGenOpts();
@@ -1033,6 +1135,11 @@
if (!codeGenOpts.OffloadObjects.empty())
embedOffloadObjects();
+ StandaloneBackendConsumer m(diags, codeGenOpts);
+
+ llvmModule->getContext().setDiagnosticHandler(
+ std::make_unique<StandaloneBackendConsumer>(m));
+
// write optimization-record
llvm::Expected<std::unique_ptr<llvm::ToolOutputFile>> optRecordFileOrErr =
setupLLVMOptimizationRemarks(
Index: flang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- flang/lib/Frontend/CompilerInvocation.cpp
+++ flang/lib/Frontend/CompilerInvocation.cpp
@@ -153,6 +153,63 @@
return true;
}
+/// Parse a remark command line argument. It may be missing, disabled/enabled by
+/// '-R[no-]group' or specified with a regular expression by '-Rgroup=regexp'.
+/// On top of that, it can be disabled/enabled globally by '-R[no-]everything'.
+static CodeGenOptions::OptRemark
+parseOptimizationRemark(clang::DiagnosticsEngine &diags,
+ llvm::opt::ArgList &args, llvm::opt::OptSpecifier optEq,
+ llvm::StringRef name) {
+ CodeGenOptions::OptRemark result;
+
+ auto initializeResultPattern = [&diags, &args,
+ &result](const llvm::opt::Arg *a,
+ llvm::StringRef pattern) {
+ result.Pattern = pattern.str();
+
+ std::string regexError;
+ result.Regex = std::make_shared<llvm::Regex>(result.Pattern);
+ if (!result.Regex->isValid(regexError)) {
+ diags.Report(clang::diag::err_drv_optimization_remark_pattern)
+ << regexError << a->getAsString(args);
+ return false;
+ }
+
+ return true;
+ };
+
+ for (llvm::opt::Arg *a : args) {
+ if (a->getOption().matches(clang::driver::options::OPT_R_Joined)) {
+ llvm::StringRef value = a->getValue();
+
+ if (value == name)
+ result.Kind = CodeGenOptions::RemarkKind::RK_Enabled;
+ else if (value == "everything")
+ result.Kind = CodeGenOptions::RemarkKind::RK_EnabledEverything;
+ else if (value.split('-') == std::make_pair(llvm::StringRef("no"), name))
+ result.Kind = CodeGenOptions::RemarkKind::RK_Disabled;
+ else if (value == "no-everything")
+ result.Kind = CodeGenOptions::RemarkKind::RK_DisabledEverything;
+ else
+ continue;
+
+ if (result.Kind == CodeGenOptions::RemarkKind::RK_Disabled ||
+ result.Kind == CodeGenOptions::RemarkKind::RK_DisabledEverything) {
+ result.Pattern = "";
+ result.Regex = nullptr;
+ } else {
+ initializeResultPattern(a, ".*");
+ }
+ } else if (a->getOption().matches(optEq)) {
+ result.Kind = CodeGenOptions::RemarkKind::RK_WithPattern;
+ if (!initializeResultPattern(a, a->getValue()))
+ return CodeGenOptions::OptRemark();
+ }
+ }
+
+ return result;
+}
+
static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,
llvm::opt::ArgList &args,
clang::DiagnosticsEngine &diags) {
@@ -194,13 +251,42 @@
args.getLastArg(clang::driver::options::OPT_opt_record_file))
opts.OptRecordFile = a->getValue();
- if (const llvm::opt::Arg *a =
- args.getLastArg(clang::driver::options::OPT_opt_record_format))
- opts.OptRecordFormat = a->getValue();
+ bool needLocTracking = false;
+
+ if (!opts.OptRecordFile.empty())
+ needLocTracking = true;
if (const llvm::opt::Arg *a =
- args.getLastArg(clang::driver::options::OPT_opt_record_passes))
+ args.getLastArg(clang::driver::options::OPT_opt_record_passes)) {
opts.OptRecordPasses = a->getValue();
+ needLocTracking = true;
+ }
+
+ if (const llvm::opt::Arg *a =
+ args.getLastArg(clang::driver::options::OPT_opt_record_format)) {
+ opts.OptRecordFormat = a->getValue();
+ needLocTracking = true;
+ }
+
+ opts.OptimizationRemark = parseOptimizationRemark(
+ diags, args, clang::driver::options::OPT_Rpass_EQ, "pass");
+
+ opts.OptimizationRemarkMissed = parseOptimizationRemark(
+ diags, args, clang::driver::options::OPT_Rpass_missed_EQ, "pass-missed");
+
+ opts.OptimizationRemarkAnalysis = parseOptimizationRemark(
+ diags, args, clang::driver::options::OPT_Rpass_analysis_EQ,
+ "pass-analysis");
+
+ needLocTracking |= opts.OptimizationRemark.hasValidPattern() ||
+ opts.OptimizationRemarkMissed.hasValidPattern() ||
+ opts.OptimizationRemarkAnalysis.hasValidPattern();
+
+ // If the user requested a flag that requires source locations available in
+ // the backend, make sure that the backend tracks source location information.
+ if (needLocTracking &&
+ opts.getDebugInfo() == llvm::codegenoptions::NoDebugInfo)
+ opts.setDebugInfo(llvm::codegenoptions::LocTrackingOnly);
if (auto *a = args.getLastArg(clang::driver::options::OPT_save_temps_EQ))
opts.SaveTempsDir = a->getValue();
@@ -697,6 +783,7 @@
// Default to off for `flang-new -fc1`.
res.getFrontendOpts().showColors =
parseShowColorsArgs(args, /*defaultDiagColor=*/false);
+ res.getDiagnosticOpts().ShowColors = res.getFrontendOpts().showColors;
return diags.getNumErrors() == numErrorsBefore;
}
@@ -903,6 +990,28 @@
return true;
}
+static void addDiagnosticArgs(const llvm::opt::ArgList &args,
+ llvm::opt::OptSpecifier group,
+ llvm::opt::OptSpecifier groupWithValue,
+ std::vector<std::string> &diagnostics) {
+ for (auto *a : args.filtered(group)) {
+ if (a->getOption().getKind() == llvm::opt::Option::FlagClass) {
+ // The argument is a pure flag (such as OPT_Wall or OPT_Wdeprecated). Add
+ // its name (minus the "W" or "R" at the beginning) to the diagnostics.
+ diagnostics.push_back(
+ std::string(a->getOption().getName().drop_front(1)));
+ } else if (a->getOption().matches(groupWithValue)) {
+ // This is -Wfoo= or -Rfoo=, where foo is the name of the diagnostic
+ // group. Add only the group name to the diagnostics.
+ diagnostics.push_back(
+ std::string(a->getOption().getName().drop_front(1).rtrim("=-")));
+ } else {
+ // Otherwise, add its value (for OPT_W_Joined and similar).
+ diagnostics.push_back(a->getValue());
+ }
+ }
+}
+
bool CompilerInvocation::createFromArgs(
CompilerInvocation &res, llvm::ArrayRef<const char *> commandLineArgs,
clang::DiagnosticsEngine &diags, const char *argv0) {
@@ -959,6 +1068,10 @@
res.loweringOpts.setNoPPCNativeVecElemOrder(true);
}
+ addDiagnosticArgs(args, clang::driver::options::OPT_R_Group,
+ clang::driver::options::OPT_R_value_Group,
+ res.getDiagnosticOpts().Remarks);
+
success &= parseFrontendArgs(res.getFrontendOpts(), args, diags);
parseTargetArgs(res.getTargetOpts(), args);
parsePreprocessorArgs(res.getPreprocessorOpts(), args);
Index: flang/include/flang/Frontend/CodeGenOptions.h
===================================================================
--- flang/include/flang/Frontend/CodeGenOptions.h
+++ flang/include/flang/Frontend/CodeGenOptions.h
@@ -69,6 +69,53 @@
/// The format used for serializing remarks (default: YAML)
std::string OptRecordFormat;
+ enum class RemarkKind {
+ RK_Missing, // Remark argument not present on the command line.
+ RK_Enabled, // Remark enabled via '-Rgroup'.
+ RK_EnabledEverything, // Remark enabled via '-Reverything'.
+ RK_Disabled, // Remark disabled via '-Rno-group'.
+ RK_DisabledEverything, // Remark disabled via '-Rno-everything'.
+ RK_WithPattern, // Remark pattern specified via '-Rgroup=regexp'.
+ };
+
+ /// Optimization remark with an optional regular expression pattern.
+ struct OptRemark {
+ RemarkKind Kind = RemarkKind::RK_Missing;
+ std::string Pattern;
+ std::shared_ptr<llvm::Regex> Regex;
+
+ /// By default, optimization remark is missing.
+ OptRemark() = default;
+
+ /// Returns true iff the optimization remark holds a valid regular
+ /// expression.
+ bool hasValidPattern() const { return Regex != nullptr; }
+
+ /// Matches the given string against the regex, if there is some.
+ bool patternMatches(llvm::StringRef string) const {
+ return hasValidPattern() && Regex->match(string);
+ }
+ };
+
+ /// Selected optimizations for which we should enable optimization remarks.
+ /// Transformation passes whose name matches the contained (optional) regular
+ /// expression (and support this feature), will emit a diagnostic whenever
+ /// they perform a transformation.
+ OptRemark OptimizationRemark;
+
+ /// Selected optimizations for which we should enable missed optimization
+ /// remarks. Transformation passes whose name matches the contained (optional)
+ /// regular expression (and support this feature), will emit a diagnostic
+ /// whenever they tried but failed to perform a transformation.
+ OptRemark OptimizationRemarkMissed;
+
+ /// Selected optimizations for which we should enable optimization analyses.
+ /// Transformation passes whose name matches the contained (optional) regular
+ /// expression (and support this feature), will emit a diagnostic whenever
+ /// they want to explain why they decided to apply or not apply a given
+ /// transformation.
+ OptRemark OptimizationRemarkAnalysis;
+
// Define accessors/mutators for code generation options of enumeration type.
#define CODEGENOPT(Name, Bits, Default)
#define ENUM_CODEGENOPT(Name, Type, Bits, Default) \
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits