diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -806,18 +806,18 @@ def Qunused_arguments : Flag<["-"], "Qunused-arguments">, Flags<[NoXarchOption, CoreOption]>, HelpText<"Don't emit warning for unused driver arguments">; def Q : Flag<["-"], "Q">, IgnoredGCCCompat; -def Rpass_EQ : Joined<["-"], "Rpass=">, Group, Flags<[CC1Option]>, +def Rpass_EQ : Joined<["-"], "Rpass=">, Group, Flags<[CC1Option, FlangOption, FC1Option]>, HelpText<"Report transformations performed by optimization passes whose " "name matches the given POSIX regular expression">; def Rpass_missed_EQ : Joined<["-"], "Rpass-missed=">, Group, - Flags<[CC1Option]>, + Flags<[CC1Option, FlangOption, FC1Option]>, HelpText<"Report missed transformations by optimization passes whose " "name matches the given POSIX regular expression">; def Rpass_analysis_EQ : Joined<["-"], "Rpass-analysis=">, Group, - Flags<[CC1Option]>, + Flags<[CC1Option, FlangOption, FC1Option]>, HelpText<"Report transformation analysis from optimization passes whose " "name matches the given POSIX regular expression">; -def R_Joined : Joined<["-"], "R">, Group, Flags<[CC1Option, CoreOption]>, +def R_Joined : Joined<["-"], "R">, Group, Flags<[CC1Option, CoreOption, FlangOption, FC1Option]>, MetaVarName<"">, HelpText<"Enable the specified remark">; def S : Flag<["-"], "S">, Flags<[NoXarchOption,CC1Option,FlangOption,FC1Option]>, Group, HelpText<"Only run preprocess and compilation steps">; diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp --- a/clang/lib/Basic/DiagnosticIDs.cpp +++ b/clang/lib/Basic/DiagnosticIDs.cpp @@ -771,9 +771,8 @@ // diagnostics. if (Diag.FatalErrorOccurred) { if (DiagLevel >= DiagnosticIDs::Error && - Diag.Client->IncludeInDiagnosticCounts()) { + Diag.Client->IncludeInDiagnosticCounts()) ++Diag.NumErrors; - } return false; } @@ -794,9 +793,8 @@ Diag.UncompilableErrorOccurred = true; Diag.ErrorOccurred = true; - if (Diag.Client->IncludeInDiagnosticCounts()) { + if (Diag.Client->IncludeInDiagnosticCounts()) ++Diag.NumErrors; - } // If we've emitted a lot of errors, emit a fatal error instead of it to // stop a flood of bogus errors. diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -769,9 +769,7 @@ if (D.getHotness()) MsgStream << " (hotness: " << *D.getHotness() << ")"; - Diags.Report(Loc, DiagID) - << AddFlagValue(D.getPassName()) - << MsgStream.str(); + Diags.Report(Loc, DiagID) << AddFlagValue(D.getPassName()) << MsgStream.str(); if (BadDebugInfo) // If we were not able to translate the file:line:col information diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -516,6 +516,9 @@ // Add Codegen options addCodegenOptions(Args, CmdArgs); + // -rpass flags + Args.AddAllArgs(CmdArgs, options::OPT_R_Group); + // Remarks can be enabled with any of the `-f.*optimization-record.*` flags. if (willEmitRemarks(Args)) renderRemarksOptions(Args, CmdArgs, Input); diff --git a/flang/include/flang/Frontend/CodeGenOptions.h b/flang/include/flang/Frontend/CodeGenOptions.h --- a/flang/include/flang/Frontend/CodeGenOptions.h +++ b/flang/include/flang/Frontend/CodeGenOptions.h @@ -69,6 +69,53 @@ /// The format used for serializing remarks (default: YAML) std::string OptRecordFormat; + enum 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 = RK_Missing; + std::string Pattern; + std::shared_ptr 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) \ diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/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(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::RK_Enabled; + else if (Value == "everything") + Result.Kind = CodeGenOptions::RK_EnabledEverything; + else if (Value.split('-') == std::make_pair(llvm::StringRef("no"), Name)) + Result.Kind = CodeGenOptions::RK_Disabled; + else if (Value == "no-everything") + Result.Kind = CodeGenOptions::RK_DisabledEverything; + else + continue; + + if (Result.Kind == CodeGenOptions::RK_Disabled || + Result.Kind == CodeGenOptions::RK_DisabledEverything) { + Result.Pattern = ""; + Result.Regex = nullptr; + } else { + InitializeResultPattern(A, ".*"); + } + } else if (A->getOption().matches(OptEQ)) { + Result.Kind = CodeGenOptions::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(); @@ -903,6 +989,28 @@ return true; } +static void addDiagnosticArgs(const llvm::opt::ArgList &Args, + llvm::opt::OptSpecifier Group, + llvm::opt::OptSpecifier GroupWithValue, + std::vector &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 commandLineArgs, clang::DiagnosticsEngine &diags, const char *argv0) { @@ -954,6 +1062,10 @@ res.loweringOpts.setPolymorphicTypeImpl(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); diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -48,6 +48,8 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/BitcodeWriterPass.h" +#include "llvm/IR/DiagnosticHandler.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Verifier.h" @@ -67,6 +69,7 @@ #include "llvm/TargetParser/TargetParser.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include +#include #include using namespace Fortran::frontend; @@ -923,6 +926,98 @@ 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); + + // Render message. + std::string Msg; + llvm::raw_string_ostream MsgStream(Msg); + MsgStream << D.getMsg(); + + // 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(&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(DI)); + break; + case llvm::DK_OptimizationRemarkMissed: + OptimizationRemarkHandler(llvm::cast(DI)); + break; + case llvm::DK_OptimizationRemarkAnalysis: + OptimizationRemarkHandler( + llvm::cast(DI)); + break; + default: + break; + } + return true; + } +}; + void CodeGenAction::embedOffloadObjects() { CompilerInstance &ci = this->getInstance(); const auto &cgOpts = ci.getInvocation().getCodeGenOpts(); @@ -1033,6 +1128,11 @@ if (!codeGenOpts.OffloadObjects.empty()) embedOffloadObjects(); + StandaloneBackendConsumer M(diags, codeGenOpts); + + llvmModule->getContext().setDiagnosticHandler( + std::make_unique(M)); + // write optimization-record llvm::Expected> optRecordFileOrErr = setupLLVMOptimizationRemarks( diff --git a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp --- a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -27,6 +27,7 @@ #include "llvm/Option/Option.h" #include "llvm/Support/BuryPointer.h" #include "llvm/Support/CommandLine.h" +#include namespace Fortran::frontend { @@ -100,6 +101,72 @@ llvm_unreachable("Invalid program action!"); } +static void EmitUnknownDiagWarning(clang::DiagnosticsEngine &Diags, + clang::diag::Flavor Flavor, + llvm::StringRef Prefix, + llvm::StringRef Opt) { + llvm::StringRef Suggestion = + clang::DiagnosticIDs::getNearestOption(Flavor, Opt); + Diags.Report(clang::diag::warn_unknown_diag_option) + << (Flavor == clang::diag::Flavor::WarningOrError ? 0 : 1) + << (Prefix.str() += std::string(Opt)) << !Suggestion.empty() + << (Prefix.str() += std::string(Suggestion)); +} + +static void processWarningOptions(clang::DiagnosticsEngine &Diags, + const clang::DiagnosticOptions &Opts, + bool ReportDiags) { + + llvm::SmallVector _Diags; + const llvm::IntrusiveRefCntPtr DiagIDs = + Diags.getDiagnosticIDs(); + // We parse the warning options twice. The first pass sets diagnostic state, + // while the second pass reports warnings/errors. This has the effect that + // we follow the more canonical "last option wins" paradigm when there are + // conflicting options. + for (unsigned Report = 0, ReportEnd = 2; Report != ReportEnd; ++Report) { + bool SetDiagnostic = (Report == 0); + + // If we've set the diagnostic state and are not reporting diagnostics then + // we're done. + if (!SetDiagnostic && !ReportDiags) + break; + + for (unsigned i = 0, e = Opts.Remarks.size(); i != e; ++i) { + llvm::StringRef Opt = Opts.Remarks[i]; + const auto Flavor = clang::diag::Flavor::Remark; + + // Check to see if this warning starts with "no-", if so, this is a + // negative form of the option. + bool IsPositive = !Opt.startswith("no-"); + if (!IsPositive) + Opt = Opt.substr(3); + + auto Severity = IsPositive ? clang::diag::Severity::Remark + : clang::diag::Severity::Ignored; + + // -Reverything sets the state of all remarks. Note that all remarks are + // in remark groups, so we don't need a separate 'all remarks enabled' + // flag. + if (Opt == "everything") { + if (SetDiagnostic) + Diags.setSeverityForAll(Flavor, Severity); + continue; + } + + if (Report) { + if (DiagIDs->getDiagnosticsInGroup(Flavor, Opt, _Diags)) + EmitUnknownDiagWarning(Diags, Flavor, IsPositive ? "-R" : "-Rno-", + Opt); + } else { + Diags.setSeverityForGroup(Flavor, Opt, + IsPositive ? clang::diag::Severity::Remark + : clang::diag::Severity::Ignored); + } + } + } +} + bool executeCompilerInvocation(CompilerInstance *flang) { // Honor -help. if (flang->getFrontendOpts().showHelp) { @@ -166,6 +233,9 @@ // Honor color diagnostics. flang->getDiagnosticOpts().ShowColors = flang->getFrontendOpts().showColors; + processWarningOptions(flang->getDiagnostics(), flang->getDiagnosticOpts(), + false); + // Create and execute the frontend action. std::unique_ptr act(createFrontendAction(*flang)); if (!act) diff --git a/flang/test/Driver/driver-help-hidden.f90 b/flang/test/Driver/driver-help-hidden.f90 --- a/flang/test/Driver/driver-help-hidden.f90 +++ b/flang/test/Driver/driver-help-hidden.f90 @@ -91,6 +91,10 @@ ! CHECK-NEXT: -print-effective-triple Print the effective target triple ! CHECK-NEXT: -print-target-triple Print the normalized target triple ! CHECK-NEXT: -P Disable linemarker output in -E mode +! CHECK-NEXT: -Rpass-analysis= Report transformation analysis from optimization passes whose name matches the given POSIX regular expression +! CHECK-NEXT: -Rpass-missed= Report missed transformations by optimization passes whose name matches the given POSIX regular expression +! CHECK-NEXT: -Rpass= Report transformations performed by optimization passes whose name matches the given POSIX regular expression +! CHECK-NEXT: -R Enable the specified remark ! CHECK-NEXT: -save-temps= Save intermediate compilation results. ! CHECK-NEXT: -save-temps Save intermediate compilation results ! CHECK-NEXT: -std= Language standard to compile for diff --git a/flang/test/Driver/driver-help.f90 b/flang/test/Driver/driver-help.f90 --- a/flang/test/Driver/driver-help.f90 +++ b/flang/test/Driver/driver-help.f90 @@ -87,6 +87,10 @@ ! HELP-NEXT: -print-effective-triple Print the effective target triple ! HELP-NEXT: -print-target-triple Print the normalized target triple ! HELP-NEXT: -P Disable linemarker output in -E mode +! HELP-NEXT: -Rpass-analysis= Report transformation analysis from optimization passes whose name matches the given POSIX regular expression +! HELP-NEXT: -Rpass-missed= Report missed transformations by optimization passes whose name matches the given POSIX regular expression +! HELP-NEXT: -Rpass= Report transformations performed by optimization passes whose name matches the given POSIX regular expression +! HELP-NEXT: -R Enable the specified remark ! HELP-NEXT: -save-temps= Save intermediate compilation results. ! HELP-NEXT: -save-temps Save intermediate compilation results ! HELP-NEXT: -std= Language standard to compile for @@ -206,6 +210,10 @@ ! HELP-FC1-NEXT: -pic-level Value for __PIC__ ! HELP-FC1-NEXT: -plugin Use the named plugin action instead of the default action (use "help" to list available options) ! HELP-FC1-NEXT: -P Disable linemarker output in -E mode +! HELP-FC1-NEXT: -Rpass-analysis= Report transformation analysis from optimization passes whose name matches the given POSIX regular expression +! HELP-FC1-NEXT: -Rpass-missed= Report missed transformations by optimization passes whose name matches the given POSIX regular expression +! HELP-FC1-NEXT: -Rpass= Report transformations performed by optimization passes whose name matches the given POSIX regular expression +! HELP-FC1-NEXT: -R Enable the specified remark ! HELP-FC1-NEXT: -save-temps= Save intermediate compilation results. ! HELP-FC1-NEXT: -save-temps Save intermediate compilation results ! HELP-FC1-NEXT: -std= Language standard to compile for diff --git a/flang/test/Driver/frontend-forwarding.f90 b/flang/test/Driver/frontend-forwarding.f90 --- a/flang/test/Driver/frontend-forwarding.f90 +++ b/flang/test/Driver/frontend-forwarding.f90 @@ -20,6 +20,13 @@ ! RUN: -flang-experimental-hlfir \ ! RUN: -mllvm -print-before-all \ ! RUN: -save-temps=obj \ +! RUN: -Rpass \ +! RUN: -Rpass-missed \ +! RUN: -Rpass-analysis \ +! RUN: -Rno-pass \ +! RUN: -Reverything \ +! RUN: -Rno-everything \ +! RUN: -Rpass=inline \ ! RUN: -P \ ! RUN: | FileCheck %s @@ -40,5 +47,12 @@ ! CHECK: "-fversion-loops-for-stride" ! CHECK: "-flang-experimental-polymorphism" ! CHECK: "-flang-experimental-hlfir" +! CHECK: "-Rpass" +! CHECK: "-Rpass-missed" +! CHECK: "-Rpass-analysis" +! CHECK: "-Rno-pass" +! CHECK: "-Reverything" +! CHECK: "-Rno-everything" +! CHECK: "-Rpass=inline" ! CHECK: "-mllvm" "-print-before-all" ! CHECK: "-save-temps=obj" diff --git a/flang/test/Driver/optimization-remark.f90 b/flang/test/Driver/optimization-remark.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Driver/optimization-remark.f90 @@ -0,0 +1,35 @@ +! 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 full -Rpass message is emitted +! RUN: %flang %s -O1 -Rpass=loop-delete 2>&1 | FileCheck %s + + +! CHECK: remark: Loop deleted because it is invariant +! CHECK-REMARKS: remark: +! CHECK-NO-REMARKS-NOT: remark: + + +program forttest + implicit none + real, dimension(1:50) :: aR1 + integer :: n + + do n = 1,50 + aR1(n) = n * 1 + end do + +end program forttest diff --git a/flang/tools/flang-driver/driver.cpp b/flang/tools/flang-driver/driver.cpp --- a/flang/tools/flang-driver/driver.cpp +++ b/flang/tools/flang-driver/driver.cpp @@ -30,6 +30,7 @@ #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/Host.h" +#include #include using llvm::StringRef;