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,9 +287,19 @@ /// -fsymbol-partition (see https://lld.llvm.org/Partitions.html). std::string SymbolPartition; - /// Regular expression and the string it was created from. + 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 RemarkPattern { - std::string Pattern; + RemarkKind Kind; + std::string Value; std::shared_ptr Regex; explicit operator bool() const { return Regex != nullptr; } 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,70 @@ << "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::RemarkPattern &Pattern) { + if (Pattern) { + GenerateArg(Args, OptEQ, Pattern.Value, SA); + } else if (Pattern.Kind == CodeGenOptions::RK_Enabled) { + GenerateArg(Args, OPT_R_Joined, Name, SA); + } else if (Pattern.Kind == CodeGenOptions::RK_Disabled) { + GenerateArg(Args, OPT_R_Joined, StringRef("no-") + Name, SA); + } +}; + +/// Parse a remark command line argument. It may be missing, disabled via +/// '-Rno-group', enabled via '-Rgroup' or specified with a regular expression +/// via '-Rgroup=regexp'. On top of that, it can be disabled/enabled globally by +/// '-R[no-]everything'. The \p Kind and \p Pattern are initialized accordingly. +static void ParseOptimizationRemark(DiagnosticsEngine &Diags, ArgList &Args, + OptSpecifier OptEQ, StringRef Name, + CodeGenOptions::RemarkPattern &Pattern) { + CodeGenOptions::RemarkPattern Result{CodeGenOptions::RK_Missing, "", nullptr}; + + auto InitializePattern = + [&Diags, &Args](const Arg *A, CodeGenOptions::RemarkPattern &Result) { + Result.Value = A->getValue(); + + std::string RegexError; + Result.Regex = std::make_shared(Result.Value); + 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 (!InitializePattern(A, Result)) + return; + } + } + + if (Result.Kind == CodeGenOptions::RK_Disabled || + Result.Kind == CodeGenOptions::RK_DisabledEverything) { + Result.Value = ""; + Result.Regex = nullptr; + } + Pattern = Result; } static bool parseDiagnosticLevelMask(StringRef FlagName, @@ -1483,16 +1533,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.OptimizationRemarkPattern); - if (Opts.OptimizationRemarkMissedPattern) - GenerateArg(Args, OPT_Rpass_missed_EQ, - Opts.OptimizationRemarkMissedPattern.Pattern, SA); + GenerateOptimizationRemark(Args, SA, OPT_Rpass_missed_EQ, "pass-missed", + Opts.OptimizationRemarkMissedPattern); - if (Opts.OptimizationRemarkAnalysisPattern) - GenerateArg(Args, OPT_Rpass_analysis_EQ, - Opts.OptimizationRemarkAnalysisPattern.Pattern, SA); + GenerateOptimizationRemark(Args, SA, OPT_Rpass_analysis_EQ, "pass-analysis", + Opts.OptimizationRemarkAnalysisPattern); GenerateArg(Args, OPT_fdiagnostics_hotness_threshold_EQ, Opts.DiagnosticsHotnessThreshold @@ -1859,23 +1907,18 @@ NeedLocTracking = true; } - if (Arg *A = Args.getLastArg(OPT_Rpass_EQ)) { - Opts.OptimizationRemarkPattern = - GenerateOptimizationRemarkRegex(Diags, Args, A); - NeedLocTracking = true; - } + ParseOptimizationRemark(Diags, Args, OPT_Rpass_EQ, "pass", + Opts.OptimizationRemarkPattern); - if (Arg *A = Args.getLastArg(OPT_Rpass_missed_EQ)) { - Opts.OptimizationRemarkMissedPattern = - GenerateOptimizationRemarkRegex(Diags, Args, A); - NeedLocTracking = true; - } + ParseOptimizationRemark(Diags, Args, OPT_Rpass_missed_EQ, "pass-missed", + Opts.OptimizationRemarkMissedPattern); - if (Arg *A = Args.getLastArg(OPT_Rpass_analysis_EQ)) { - Opts.OptimizationRemarkAnalysisPattern = - GenerateOptimizationRemarkRegex(Diags, Args, A); - NeedLocTracking = true; - } + ParseOptimizationRemark(Diags, Args, OPT_Rpass_analysis_EQ, "pass-analysis", + Opts.OptimizationRemarkAnalysisPattern); + + NeedLocTracking |= Opts.OptimizationRemarkPattern || + Opts.OptimizationRemarkMissedPattern || + Opts.OptimizationRemarkAnalysisPattern; bool UsingSampleProfile = !Opts.SampleProfileFile.empty(); bool UsingProfile = UsingSampleProfile || @@ -2294,8 +2337,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,