diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -287,37 +287,52 @@ /// -fsymbol-partition (see https://lld.llvm.org/Partitions.html). std::string SymbolPartition; - /// Regular expression and the string it was created from. - struct RemarkPattern { + 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; std::string Pattern; std::shared_ptr Regex; - explicit operator bool() const { return Regex != nullptr; } + /// By default, optimization remark is missing. + OptRemark() : Kind(RK_Missing), Pattern(""), Regex(nullptr) {} + + /// Returns true iff the optimization remark holds a valid regular + /// expression. + bool hasValidPattern() const { return Regex != nullptr; } - llvm::Regex *operator->() const { return Regex.get(); } + /// Matches the given string against the regex, if there is some. + bool patternMatches(StringRef String) const { + return hasValidPattern() && Regex->match(String); + } }; - /// 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. - RemarkPattern OptimizationRemarkPattern; - - /// Regular expression to select optimizations for which we should enable - /// missed optimization remarks. Transformation passes whose name matches this - /// expression (and support this feature), will emit a diagnostic - /// whenever they tried but failed to perform a transformation. This is - /// enabled by the -Rpass-missed=regexp flag. - RemarkPattern OptimizationRemarkMissedPattern; - - /// Regular expression to select optimizations for which we should enable - /// optimization analyses. Transformation passes whose name matches this - /// 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. This is enabled by the -Rpass-analysis=regexp - /// flag. - RemarkPattern OptimizationRemarkAnalysisPattern; + /// 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; /// Set of files defining the rules for the symbol rewriting. std::vector RewriteMapFiles; 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 @@ -60,22 +60,19 @@ bool handleDiagnostics(const DiagnosticInfo &DI) override; bool isAnalysisRemarkEnabled(StringRef PassName) const override { - return (CodeGenOpts.OptimizationRemarkAnalysisPattern && - CodeGenOpts.OptimizationRemarkAnalysisPattern->match(PassName)); + return CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(PassName); } bool isMissedOptRemarkEnabled(StringRef PassName) const override { - return (CodeGenOpts.OptimizationRemarkMissedPattern && - CodeGenOpts.OptimizationRemarkMissedPattern->match(PassName)); + return CodeGenOpts.OptimizationRemarkMissed.patternMatches(PassName); } bool isPassedOptRemarkEnabled(StringRef PassName) const override { - return (CodeGenOpts.OptimizationRemarkPattern && - CodeGenOpts.OptimizationRemarkPattern->match(PassName)); + return CodeGenOpts.OptimizationRemark.patternMatches(PassName); } bool isAnyRemarkEnabled() const override { - return (CodeGenOpts.OptimizationRemarkAnalysisPattern || - CodeGenOpts.OptimizationRemarkMissedPattern || - CodeGenOpts.OptimizationRemarkPattern); + return CodeGenOpts.OptimizationRemarkAnalysis.hasValidPattern() || + CodeGenOpts.OptimizationRemarkMissed.hasValidPattern() || + CodeGenOpts.OptimizationRemark.hasValidPattern(); } private: @@ -722,15 +719,13 @@ 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.OptimizationRemarkPattern && - CodeGenOpts.OptimizationRemarkPattern->match(D.getPassName())) + if (CodeGenOpts.OptimizationRemark.patternMatches(D.getPassName())) EmitOptimizationMessage(D, 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.OptimizationRemarkMissedPattern && - CodeGenOpts.OptimizationRemarkMissedPattern->match(D.getPassName())) + if (CodeGenOpts.OptimizationRemarkMissed.patternMatches(D.getPassName())) EmitOptimizationMessage( D, diag::remark_fe_backend_optimization_remark_missed); } else { @@ -741,8 +736,7 @@ ShouldAlwaysPrint = ORA->shouldAlwaysPrint(); if (ShouldAlwaysPrint || - (CodeGenOpts.OptimizationRemarkAnalysisPattern && - CodeGenOpts.OptimizationRemarkAnalysisPattern->match(D.getPassName()))) + CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(D.getPassName())) EmitOptimizationMessage( D, diag::remark_fe_backend_optimization_remark_analysis); } @@ -755,8 +749,7 @@ // regular expression that matches the name of the pass name in \p D. if (D.shouldAlwaysPrint() || - (CodeGenOpts.OptimizationRemarkAnalysisPattern && - CodeGenOpts.OptimizationRemarkAnalysisPattern->match(D.getPassName()))) + CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(D.getPassName())) EmitOptimizationMessage( D, diag::remark_fe_backend_optimization_remark_analysis_fpcommute); } @@ -768,8 +761,7 @@ // regular expression that matches the name of the pass name in \p D. if (D.shouldAlwaysPrint() || - (CodeGenOpts.OptimizationRemarkAnalysisPattern && - CodeGenOpts.OptimizationRemarkAnalysisPattern->match(D.getPassName()))) + CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(D.getPassName())) EmitOptimizationMessage( D, diag::remark_fe_backend_optimization_remark_analysis_aliasing); } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1162,20 +1162,69 @@ << "a filename"; } -/// Create a new Regex instance out of the string value in \p RpassArg. -/// It returns the string and a pointer to the newly generated Regex instance. -static CodeGenOptions::RemarkPattern -GenerateOptimizationRemarkRegex(DiagnosticsEngine &Diags, ArgList &Args, - Arg *RpassArg) { - StringRef Val = RpassArg->getValue(); - std::string RegexError; - std::shared_ptr Pattern = std::make_shared(Val); - if (!Pattern->isValid(RegexError)) { - Diags.Report(diag::err_drv_optimization_remark_pattern) - << RegexError << RpassArg->getAsString(Args); - Pattern.reset(); - } - return {std::string(Val), Pattern}; +/// Generate a remark argument. This is an inverse of `ParseOptimizationRemark`. +static void +GenerateOptimizationRemark(SmallVectorImpl &Args, + CompilerInvocation::StringAllocator SA, + OptSpecifier OptEQ, StringRef Name, + const CodeGenOptions::OptRemark &Remark) { + if (Remark.hasValidPattern()) { + GenerateArg(Args, OptEQ, Remark.Pattern, SA); + } else if (Remark.Kind == CodeGenOptions::RK_Enabled) { + GenerateArg(Args, OPT_R_Joined, Name, SA); + } else if (Remark.Kind == CodeGenOptions::RK_Disabled) { + GenerateArg(Args, OPT_R_Joined, StringRef("no-") + Name, SA); + } +}; + +/// 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(DiagnosticsEngine &Diags, ArgList &Args, + OptSpecifier OptEQ, StringRef Name) { + CodeGenOptions::OptRemark Result; + + auto InitializeResultPattern = [&Diags, &Args, &Result](const Arg *A) { + Result.Pattern = A->getValue(); + + std::string RegexError; + Result.Regex = std::make_shared(Result.Pattern); + if (!Result.Regex->isValid(RegexError)) { + Diags.Report(diag::err_drv_optimization_remark_pattern) + << RegexError << A->getAsString(Args); + return false; + } + + return true; + }; + + for (Arg *A : Args) { + if (A->getOption().matches(OPT_R_Joined)) { + 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(StringRef("no"), Name)) + Result.Kind = CodeGenOptions::RK_Disabled; + else if (Value == "no-everything") + Result.Kind = CodeGenOptions::RK_DisabledEverything; + } else if (A->getOption().matches(OptEQ)) { + Result.Kind = CodeGenOptions::RK_WithPattern; + if (!InitializeResultPattern(A)) + return CodeGenOptions::OptRemark(); + } + } + + if (Result.Kind == CodeGenOptions::RK_Disabled || + Result.Kind == CodeGenOptions::RK_DisabledEverything) { + Result.Pattern = ""; + Result.Regex = nullptr; + } + + return Result; } static bool parseDiagnosticLevelMask(StringRef FlagName, @@ -1480,16 +1529,14 @@ if (!Opts.OptRecordFormat.empty()) GenerateArg(Args, OPT_opt_record_format, Opts.OptRecordFormat, SA); - if (Opts.OptimizationRemarkPattern) - GenerateArg(Args, OPT_Rpass_EQ, Opts.OptimizationRemarkPattern.Pattern, SA); + GenerateOptimizationRemark(Args, SA, OPT_Rpass_EQ, "pass", + Opts.OptimizationRemark); - if (Opts.OptimizationRemarkMissedPattern) - GenerateArg(Args, OPT_Rpass_missed_EQ, - Opts.OptimizationRemarkMissedPattern.Pattern, SA); + GenerateOptimizationRemark(Args, SA, OPT_Rpass_missed_EQ, "pass-missed", + Opts.OptimizationRemarkMissed); - if (Opts.OptimizationRemarkAnalysisPattern) - GenerateArg(Args, OPT_Rpass_analysis_EQ, - Opts.OptimizationRemarkAnalysisPattern.Pattern, SA); + GenerateOptimizationRemark(Args, SA, OPT_Rpass_analysis_EQ, "pass-analysis", + Opts.OptimizationRemarkAnalysis); GenerateArg(Args, OPT_fdiagnostics_hotness_threshold_EQ, Opts.DiagnosticsHotnessThreshold @@ -1853,23 +1900,18 @@ NeedLocTracking = true; } - if (Arg *A = Args.getLastArg(OPT_Rpass_EQ)) { - Opts.OptimizationRemarkPattern = - GenerateOptimizationRemarkRegex(Diags, Args, A); - NeedLocTracking = true; - } + Opts.OptimizationRemark = + ParseOptimizationRemark(Diags, Args, OPT_Rpass_EQ, "pass"); - if (Arg *A = Args.getLastArg(OPT_Rpass_missed_EQ)) { - Opts.OptimizationRemarkMissedPattern = - GenerateOptimizationRemarkRegex(Diags, Args, A); - NeedLocTracking = true; - } + Opts.OptimizationRemarkMissed = + ParseOptimizationRemark(Diags, Args, OPT_Rpass_missed_EQ, "pass-missed"); - if (Arg *A = Args.getLastArg(OPT_Rpass_analysis_EQ)) { - Opts.OptimizationRemarkAnalysisPattern = - GenerateOptimizationRemarkRegex(Diags, Args, A); - NeedLocTracking = true; - } + Opts.OptimizationRemarkAnalysis = ParseOptimizationRemark( + Diags, Args, OPT_Rpass_analysis_EQ, "pass-analysis"); + + NeedLocTracking |= Opts.OptimizationRemark.hasValidPattern() || + Opts.OptimizationRemarkMissed.hasValidPattern() || + Opts.OptimizationRemarkAnalysis.hasValidPattern(); bool UsingSampleProfile = !Opts.SampleProfileFile.empty(); bool UsingProfile = UsingSampleProfile || @@ -2288,8 +2330,17 @@ Args.push_back(SA(StringRef("-W") + Warning)); } - for (const auto &Remark : Opts.Remarks) + for (const auto &Remark : Opts.Remarks) { + // These arguments are generated from OptimizationRemark fields of + // CodeGenOptions. + StringRef IgnoredRemarks[] = {"pass", "no-pass", + "pass-analysis", "no-pass-analysis", + "pass-missed", "no-pass-missed"}; + if (llvm::is_contained(IgnoredRemarks, Remark)) + continue; + Args.push_back(SA(StringRef("-R") + Remark)); + } } bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,