Optimize OptTable::findNearest implementation and usage
authorserge-sans-paille <sguelton@mozilla.com>
Wed, 18 Jan 2023 15:43:56 +0000 (16:43 +0100)
committerserge-sans-paille <sguelton@mozilla.com>
Thu, 19 Jan 2023 13:16:29 +0000 (14:16 +0100)
When used to find an exact match, some extra context can be used to
totally cut some computations.

This saves 1% of the instruction count when pre processing sqlite3.c
through

valgrind --tool=callgrind ./bin/clang -E sqlite3.c -o/dev/null

Differential Revision: https://reviews.llvm.org/D142026

clang/lib/Driver/Driver.cpp
llvm/include/llvm/Option/OptTable.h
llvm/lib/Option/OptTable.cpp

index 555512f..58e1090 100644 (file)
@@ -313,8 +313,8 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
     std::string Nearest;
     if (getOpts().findNearest(ArgString, Nearest, IncludedFlagsBitmask,
                               ExcludedFlagsBitmask) > 1) {
-      if (getOpts().findNearest(ArgString, Nearest, options::CC1Option) == 0 &&
-          !IsCLMode()) {
+      if (!IsCLMode() &&
+          getOpts().findExact(ArgString, Nearest, options::CC1Option)) {
         DiagID = diag::err_drv_unknown_argument_with_suggestion;
         Diags.Report(DiagID) << ArgString << "-Xclang " + Nearest;
       } else {
@@ -339,8 +339,8 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
     // Warn on joined arguments that are similar to a long argument.
     std::string ArgString = ArgStrings[A->getIndex()];
     std::string Nearest;
-    if (getOpts().findNearest("-" + ArgString, Nearest, IncludedFlagsBitmask,
-                              ExcludedFlagsBitmask) == 0)
+    if (getOpts().findExact("-" + ArgString, Nearest, IncludedFlagsBitmask,
+                            ExcludedFlagsBitmask))
       Diags.Report(diag::warn_drv_potentially_misspelled_joined_argument)
           << A->getAsString(Args) << Nearest;
   }
index 25d86c0..8f13a31 100644 (file)
@@ -175,11 +175,21 @@ public:
   /// \param [in] MinimumLength - Don't find options shorter than this length.
   /// For example, a minimum length of 3 prevents "-x" from being considered
   /// near to "-S".
+  /// \param [in] MaximumDistance - Don't find options whose distance is greater
+  /// than this value.
   ///
   /// \return The edit distance of the nearest string found.
   unsigned findNearest(StringRef Option, std::string &NearestString,
                        unsigned FlagsToInclude = 0, unsigned FlagsToExclude = 0,
-                       unsigned MinimumLength = 4) const;
+                       unsigned MinimumLength = 4,
+                       unsigned MaximumDistance = UINT_MAX - 1) const;
+
+  bool findExact(StringRef Option, std::string &ExactString,
+                 unsigned FlagsToInclude = 0,
+                 unsigned FlagsToExclude = 0) const {
+    return findNearest(Option, ExactString, FlagsToInclude, FlagsToExclude, 4,
+                       0) == 0;
+  }
 
   /// Parse a single argument; returning the new argument and
   /// updating Index.
index dea9fc0..10f0658 100644 (file)
@@ -227,12 +227,13 @@ OptTable::findByPrefix(StringRef Cur, unsigned int DisableFlags) const {
 
 unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
                                unsigned FlagsToInclude, unsigned FlagsToExclude,
-                               unsigned MinimumLength) const {
+                               unsigned MinimumLength,
+                               unsigned MaximumDistance) const {
   assert(!Option.empty());
 
   // Consider each [option prefix + option name] pair as a candidate, finding
   // the closest match.
-  unsigned BestDistance = UINT_MAX;
+  unsigned BestDistance = MaximumDistance + 1;
   SmallString<16> Candidate;
   SmallString<16> NormalizedName;
 
@@ -276,6 +277,14 @@ unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,
     // appropriate one. For example, if a user asks for "--helm", suggest
     // "--help" over "-help".
     for (auto CandidatePrefix : CandidateInfo.Prefixes) {
+      // If Candidate and NormalizedName have more than 'BestDistance'
+      // characters of difference, no need to compute the edit distance, it's
+      // going to be greater than BestDistance. Don't bother computing Candidate
+      // at all.
+      if (std::abs((ssize_t)(CandidatePrefix.size() + CandidateName.size()) -
+                   (ssize_t)NormalizedName.size()) > (ssize_t)BestDistance) {
+        continue;
+      }
       Candidate = CandidatePrefix;
       Candidate += CandidateName;
       unsigned Distance = StringRef(Candidate).edit_distance(