Skip to content

[GlobPattern] add AsLiteral to help lld determine if a symbol is literal - #215854

Merged
DataCorrupted merged 8 commits into
llvm:mainfrom
DataCorrupted:lld-glob
Aug 31, 2026
Merged

[GlobPattern] add AsLiteral to help lld determine if a symbol is literal#215854
DataCorrupted merged 8 commits into
llvm:mainfrom
DataCorrupted:lld-glob

Conversation

@DataCorrupted

@DataCorrupted DataCorrupted commented Aug 12, 2026

Copy link
Copy Markdown
Member

lld determines if a symbolName is literal by find_first_of("*?[]"), which is not accurate and ignored escape characters, we do the following:

  1. Add a new API std::optional<StringRef> asLiteral(...) that dumps the pattern as a literal string if it is one.
  2. All symbolNames are considered as GlobPattern first to leverage asLeteral to help us determine if a string is a literal. The quick path in during GlobPattern construction is if (!S.find_first_of(PrefixMetas)) return Pat;, so for strings without *?[] (most of the symbolNames), the performance should be about the same.
  3. symbolNames that are literal go back to hashing like lld did before

Added tests in lld and unit test for GlobPattern

@llvmorg-github-actions

llvmorg-github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

@llvm/pr-subscribers-lld-macho
@llvm/pr-subscribers-llvm-support

@llvm/pr-subscribers-lld

Author: Peter Rong (DataCorrupted)

Changes

lld determines if a symbolName is literal by find_first_of("*?[]"), which is not accurate and ignored escape characters, we do the following:

  1. Add a new API std::optional&lt;StringRef&gt; asLiteral(...) that dumps the pattern as a literal string if it is one.
  2. All symbolNames are considered as GlobPattern first to leverage asLeteral to help us determine if a string is a literal. The quick path in during GlobPattern construction is if (!S.find_first_of(PrefixMetas)) return Pat;, so for strings without *?[] (most of the symbolNames), the performance should be about the same.
  3. symbolNames that are literal go back to hashing like lld did before

Added tests in lld and unit test for GlobPattern


Full diff: https://github.com/llvm/llvm-project/pull/215854.diff

5 Files Affected:

  • (modified) lld/MachO/Driver.cpp (+14-5)
  • (added) lld/test/MachO/exported-symbols-list-escapes.s (+65)
  • (modified) llvm/include/llvm/Support/GlobPattern.h (+15)
  • (modified) llvm/lib/Support/GlobPattern.cpp (+30)
  • (modified) llvm/unittests/Support/GlobPatternTest.cpp (+57)
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 2864c6d28fa49..2fa959eaf7e93 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -1360,12 +1360,21 @@ void SymbolPatterns::clear() {
 }
 
 void SymbolPatterns::insert(StringRef symbolName) {
-  if (symbolName.find_first_of("*?[]") == StringRef::npos)
-    literals.insert(CachedHashStringRef(symbolName));
-  else if (Expected<GlobPattern> pattern = GlobPattern::create(symbolName))
-    globs.emplace_back(*pattern);
-  else
+  Expected<GlobPattern> pattern = GlobPattern::create(symbolName);
+  if (!pattern) {
+    llvm::consumeError(pattern.takeError());
     error("invalid symbol-name pattern: " + symbolName);
+    return;
+  }
+  // A pattern that denotes a single string is kept as a literal: literals are
+  // matched by hash lookup, and only literals seed the force-load of lazy
+  // archive members below.
+  SmallVector<char, 128> storage;
+  if (std::optional<StringRef> literal = pattern->asLiteral(storage)) {
+    literals.insert(CachedHashStringRef(saver().save(*literal)));
+    return;
+  }
+  globs.emplace_back(std::move(*pattern));
 }
 
 bool SymbolPatterns::matchLiteral(StringRef symbolName) const {
diff --git a/lld/test/MachO/exported-symbols-list-escapes.s b/lld/test/MachO/exported-symbols-list-escapes.s
new file mode 100644
index 0000000000000..169ce49435174
--- /dev/null
+++ b/lld/test/MachO/exported-symbols-list-escapes.s
@@ -0,0 +1,65 @@
+# REQUIRES: x86
+
+## An -exported_symbols_list entry may escape glob metacharacters with a
+## backslash to name a symbol literally. This matters for Objective-C direct
+## methods, whose names contain square brackets that would otherwise be parsed
+## as a character class and match nothing.
+
+# RUN: rm -rf %t; split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %t/bracket.s -o %t/bracket.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %t/anchor.s -o %t/anchor.o
+# RUN: llvm-ar --format=darwin rcs %t/bracket.a %t/bracket.o
+
+## An escaped entry is a literal: it exact-matches, and because literals seed
+## addUndefined it also force-loads the archive member that defines it.
+# RUN: %lld -dylib -exported_symbols_list %t/escaped.txt \
+# RUN:     %t/anchor.o %t/bracket.a -o %t/escaped.dylib
+# RUN: llvm-nm --extern-only %t/escaped.dylib | FileCheck --check-prefix=ESCAPED %s
+
+# ESCAPED: -[C m]D
+
+## An unescaped entry keeps its glob meaning: "[C m]" is a character class, so
+## it does not match the real symbol and nothing is force-loaded.
+# RUN: %lld -dylib -exported_symbols_list %t/unescaped.txt \
+# RUN:     %t/anchor.o %t/bracket.a -o %t/unescaped.dylib
+# RUN: llvm-nm --extern-only %t/unescaped.dylib | \
+# RUN:     FileCheck --check-prefix=UNESCAPED --allow-empty %s
+
+# UNESCAPED-NOT: -[C m]D
+
+## Escaping a star names a symbol that literally contains one, rather than
+## matching any symbol by prefix.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %t/star.s -o %t/star.o
+# RUN: %lld -dylib -exported_symbols_list %t/escaped-star.txt \
+# RUN:     %t/star.o -o %t/star.dylib
+# RUN: llvm-nm --extern-only %t/star.dylib | FileCheck --check-prefix=STAR %s
+
+# STAR-DAG: _lit*eral
+# STAR-NOT: _litoteral
+
+#--- bracket.s
+.globl "_-[C m]D"
+"_-[C m]D":
+  retq
+
+#--- anchor.s
+.globl _anchor
+_anchor:
+  retq
+
+#--- star.s
+.globl "_lit*eral"
+"_lit*eral":
+  retq
+.globl _litoteral
+_litoteral:
+  retq
+
+#--- escaped.txt
+_-\[C m\]D
+
+#--- unescaped.txt
+_-[C m]D
+
+#--- escaped-star.txt
+_lit\*eral
diff --git a/llvm/include/llvm/Support/GlobPattern.h b/llvm/include/llvm/Support/GlobPattern.h
index 8c84c93834c6b..7b4875cd093db 100644
--- a/llvm/include/llvm/Support/GlobPattern.h
+++ b/llvm/include/llvm/Support/GlobPattern.h
@@ -61,6 +61,17 @@ class GlobPattern {
   /// \returns \p true if \p S matches this glob pattern
   LLVM_ABI bool match(StringRef S) const;
 
+  /// \returns the single string this pattern matches, if the pattern contains
+  /// no unescaped metacharacters; otherwise std::nullopt. Escapes are resolved,
+  /// so `a\*b` yields `a*b`. Characters that are only special in context (`]`,
+  /// `}`, `,`) do not make a pattern non-literal.
+  ///
+  /// \p Storage is used only when escapes have to be resolved; otherwise the
+  /// result aliases the text passed to create(). The result is valid for as
+  /// long as both remain alive.
+  LLVM_ABI std::optional<StringRef>
+  asLiteral(SmallVectorImpl<char> &Storage) const;
+
   // Returns true for glob pattern "*". Can be used to avoid expensive
   // preparation/acquisition of the input for match().
   bool isTrivialMatchAll() const {
@@ -97,6 +108,8 @@ class GlobPattern {
     /// \returns \p true if \p S matches this glob pattern
     LLVM_ABI bool match(StringRef S, bool SlashAgnostic) const;
     StringRef getPat() const { return StringRef(Pat.data(), Pat.size()); }
+    /// \returns \p true if this sub-pattern matches exactly one string.
+    bool isLiteral() const { return Brackets.empty() && !HasWildcard; }
 
     // Brackets with their end position and matched bytes.
     struct Bracket {
@@ -104,6 +117,8 @@ class GlobPattern {
       BitVector Bytes;
     };
     SmallVector<Bracket, 0> Brackets;
+    // Set while parsing if an unescaped '*' or '?' is present.
+    bool HasWildcard = false;
     SmallVector<char, 0> Pat;
   };
   SmallVector<SubGlobPattern, 1> SubGlobs;
diff --git a/llvm/lib/Support/GlobPattern.cpp b/llvm/lib/Support/GlobPattern.cpp
index ebaa08cba96aa..6f78a02af4606 100644
--- a/llvm/lib/Support/GlobPattern.cpp
+++ b/llvm/lib/Support/GlobPattern.cpp
@@ -182,6 +182,17 @@ static StringRef maxPlainSubstring(StringRef S, bool SlashAgnostic) {
   return Best;
 }
 
+// Writes S into Storage with its escaping backslashes removed.
+static void unescapePattern(StringRef S, SmallVectorImpl<char> &Storage) {
+  Storage.clear();
+  Storage.reserve(S.size());
+  for (size_t I = 0, E = S.size(); I != E; ++I) {
+    if (S[I] == '\\' && I + 1 != E)
+      ++I;
+    Storage.push_back(S[I]);
+  }
+}
+
 Expected<GlobPattern> GlobPattern::create(StringRef S,
                                           std::optional<size_t> MaxSubPatterns,
                                           bool SlashAgnostic) {
@@ -225,6 +236,23 @@ Expected<GlobPattern> GlobPattern::create(StringRef S,
   return Pat;
 }
 
+std::optional<StringRef>
+GlobPattern::asLiteral(SmallVectorImpl<char> &Storage) const {
+  // The prefix and suffix are metacharacter-free by construction, so whether
+  // this pattern denotes a single string is decided by the sub-patterns, which
+  // recorded it while parsing. No sub-pattern at all means there was no
+  // metacharacter; more than one means brace expansion produced a choice.
+  if (!SubGlobs.empty() &&
+      !(SubGlobs.size() == 1 && SubGlobs[0].isLiteral()))
+    return std::nullopt;
+
+  if (!Pattern.contains('\\'))
+    return Pattern;
+
+  unescapePattern(Pattern, Storage);
+  return StringRef(Storage.data(), Storage.size());
+}
+
 Expected<GlobPattern::SubGlobPattern>
 GlobPattern::SubGlobPattern::create(StringRef S, bool SlashAgnostic) {
   SubGlobPattern Pat;
@@ -260,6 +288,8 @@ GlobPattern::SubGlobPattern::create(StringRef S, bool SlashAgnostic) {
       if (++I == E)
         return make_error<StringError>("invalid glob pattern, stray '\\'",
                                        errc::invalid_argument);
+    } else if (S[I] == '*' || S[I] == '?') {
+      Pat.HasWildcard = true;
     }
   }
   return Pat;
diff --git a/llvm/unittests/Support/GlobPatternTest.cpp b/llvm/unittests/Support/GlobPatternTest.cpp
index 35423e37a3ae0..3be79476ca0c2 100644
--- a/llvm/unittests/Support/GlobPatternTest.cpp
+++ b/llvm/unittests/Support/GlobPatternTest.cpp
@@ -39,6 +39,63 @@ TEST_F(GlobPatternTest, Wildcard) {
   EXPECT_FALSE(Pat1->match(""));
 }
 
+TEST_F(GlobPatternTest, AsLiteral) {
+  SmallVector<char, 64> Storage;
+
+  // Plain literals, including characters that are only special in context.
+  // These need no unescaping, so the result aliases the pattern.
+  for (StringRef P : {"abc", "", "a]c", "a}c", "a,c"}) {
+    Expected<GlobPattern> Pat = GlobPattern::create(P);
+    ASSERT_TRUE((bool)Pat) << P;
+    std::optional<StringRef> Lit = Pat->asLiteral(Storage);
+    ASSERT_TRUE(Lit.has_value()) << P;
+    EXPECT_EQ(*Lit, P);
+    EXPECT_EQ(Lit->data(), P.data()) << P;
+  }
+
+  // Real metacharacters are not literals.
+  for (StringRef P : {"a*c", "a?c", "a[bc]d"}) {
+    Expected<GlobPattern> Pat = GlobPattern::create(P);
+    ASSERT_TRUE((bool)Pat) << P;
+    EXPECT_FALSE(Pat->asLiteral(Storage).has_value()) << P;
+  }
+
+  // Escaped metacharacters denote a single string, with escapes resolved.
+  Expected<GlobPattern> Star = GlobPattern::create("a\\*c");
+  ASSERT_TRUE((bool)Star);
+  ASSERT_TRUE(Star->asLiteral(Storage).has_value());
+  EXPECT_EQ(*Star->asLiteral(Storage), "a*c");
+  EXPECT_TRUE(Star->match("a*c"));
+  EXPECT_FALSE(Star->match("abc"));
+
+  // The motivating case: an Objective-C direct method symbol.
+  Expected<GlobPattern> Method = GlobPattern::create("-\\[C m\\]D");
+  ASSERT_TRUE((bool)Method);
+  ASSERT_TRUE(Method->asLiteral(Storage).has_value());
+  EXPECT_EQ(*Method->asLiteral(Storage), "-[C m]D");
+  EXPECT_TRUE(Method->match("-[C m]D"));
+
+  // An unescaped bracket expression is a character class, not this symbol.
+  Expected<GlobPattern> Class = GlobPattern::create("-[C m]D");
+  ASSERT_TRUE((bool)Class);
+  EXPECT_FALSE(Class->asLiteral(Storage).has_value());
+  EXPECT_FALSE(Class->match("-[C m]D"));
+
+  // '{' is a metacharacter only when brace expansion is enabled.
+  Expected<GlobPattern> NoBraces = GlobPattern::create("a{b,c}d");
+  ASSERT_TRUE((bool)NoBraces);
+  EXPECT_TRUE(NoBraces->asLiteral(Storage).has_value());
+  Expected<GlobPattern> Braces = GlobPattern::create("a{b,c}d", /*Max=*/1024);
+  ASSERT_TRUE((bool)Braces);
+  EXPECT_FALSE(Braces->asLiteral(Storage).has_value());
+
+  // An escaped backslash is a literal backslash.
+  Expected<GlobPattern> Backslash = GlobPattern::create("a\\\\c");
+  ASSERT_TRUE((bool)Backslash);
+  ASSERT_TRUE(Backslash->asLiteral(Storage).has_value());
+  EXPECT_EQ(*Backslash->asLiteral(Storage), "a\\c");
+}
+
 TEST_F(GlobPatternTest, Escape) {
   Expected<GlobPattern> Pat1 = GlobPattern::create("\\*");
   EXPECT_TRUE((bool)Pat1);

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

✅ With the latest revision this PR passed the C/C++ code formatter.

@ellishg
ellishg requested a review from NuriAmari August 12, 2026 17:55
Comment thread lld/MachO/Driver.cpp
Comment thread llvm/unittests/Support/GlobPatternTest.cpp Outdated
Comment thread llvm/unittests/Support/GlobPatternTest.cpp Outdated
Comment thread llvm/lib/Support/GlobPattern.cpp Outdated
Comment thread lld/MachO/Driver.cpp Outdated
Comment thread llvm/include/llvm/Support/GlobPattern.h Outdated
/// result aliases the text passed to create(). The result is valid for as
/// long as both remain alive.
LLVM_ABI std::optional<StringRef>
asLiteral(SmallVectorImpl<char> &Storage) const;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
asLiteral(SmallVectorImpl<char> &Storage) const;
asLiteral(SmallString<> &Storage) const;

This allows us to use += on characters

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you can use SmallString<>, a size parameter is required e.g. SmallString<32>, but I don't want to encode that into the function parameter


std::optional<StringRef>
GlobPattern::asLiteral(SmallVectorImpl<char> &Storage) const {
// The prefix and suffix are metacharacter-free by construction, so whether

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should bail out this case too?

  if (SlashAgnostic)
    return std::nullopt;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find! Just added the corner case

Comment thread lld/MachO/Driver.cpp Outdated
// A pattern that denotes a single string is kept as a literal: literals are
// matched by hash lookup, and only literals seed the force-load of lazy
// archive members below.
SmallVector<char, 128> storage;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
SmallVector<char, 128> storage;
SmallString<128> storage;

@DataCorrupted

Copy link
Copy Markdown
Member Author

Please let me know if there are more concerns that I haven't address, or is it good to merge?

Co-authored-by: Ellis Hoag <ellis.sparky.hoag@gmail.com>
@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown

🐧 Linux x64 Test Results

  • 202990 tests passed
  • 5692 tests skipped

✅ The build succeeded and all tests passed.

@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown

🪟 Windows x64 Test Results

  • 140625 tests passed
  • 3769 tests skipped

✅ The build succeeded and all tests passed.

Comment thread llvm/lib/Support/GlobPattern.cpp Outdated
@kyulee-com

Copy link
Copy Markdown
Contributor

LGTM from the lld/Mach-O side. The Objective-C direct-method case is a strong use case for identifying escaped glob patterns as literals.

@MaskRay @vitalybuka Would appreciate a Support maintainer confirming the new API.

@kyulee-com
kyulee-com requested a review from MaskRay August 27, 2026 01:12
Co-authored-by: Ellis Hoag <ellis.sparky.hoag@gmail.com>

@ellishg ellishg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but would also like Support maintainer's eyes on this

Comment thread llvm/lib/Support/GlobPattern.cpp Outdated
Comment thread lld/MachO/Driver.cpp Outdated
@DataCorrupted

Copy link
Copy Markdown
Member Author

Thanks for the review, merging

@DataCorrupted
DataCorrupted merged commit 7b91afa into llvm:main Aug 31, 2026
12 checks passed
@llvm-ci

llvm-ci commented Aug 31, 2026

Copy link
Copy Markdown

LLVM Buildbot has detected a new failure on builder intel-sycl-gpu running on intel-sycl-gpu-01 while building lld,llvm at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/225/builds/17068

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'libarcher :: races/taskwait-depend.c' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 14
/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./bin/clang -fopenmp  -gdwarf-4 -O1 -fsanitize=thread  -I /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests -I /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src -L /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src   /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c -o /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/taskwait-depend.c.tmp -latomic && env TSAN_OPTIONS='ignore_noninstrumented_modules=0:ignore_noninstrumented_modules=1' /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/deflake.bash /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/taskwait-depend.c.tmp 2>&1 | tee /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/taskwait-depend.c.tmp.log | /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./bin/FileCheck /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c
# executed command: /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./bin/clang -fopenmp -gdwarf-4 -O1 -fsanitize=thread -I /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests -I /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src -L /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c -o /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/taskwait-depend.c.tmp -latomic
# executed command: env TSAN_OPTIONS=ignore_noninstrumented_modules=0:ignore_noninstrumented_modules=1 /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/deflake.bash /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/taskwait-depend.c.tmp
# executed command: tee /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/taskwait-depend.c.tmp.log
# executed command: /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./bin/FileCheck /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c
# RUN: at line 15
/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./bin/clang -fopenmp  -gdwarf-4 -O1 -fsanitize=thread  -I /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests -I /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src -L /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src   /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c -o /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/taskwait-depend.c.tmp -latomic && env ARCHER_OPTIONS="ignore_serial=1 report_data_leak=1" env TSAN_OPTIONS='ignore_noninstrumented_modules=0:ignore_noninstrumented_modules=1' /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/deflake.bash /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/taskwait-depend.c.tmp 2>&1 | tee /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/taskwait-depend.c.tmp.log | /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./bin/FileCheck /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c
# executed command: /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./bin/clang -fopenmp -gdwarf-4 -O1 -fsanitize=thread -I /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests -I /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src -L /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src -Wl,-rpath,/home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/runtime/src /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c -o /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/taskwait-depend.c.tmp -latomic
# executed command: env 'ARCHER_OPTIONS=ignore_serial=1 report_data_leak=1' env TSAN_OPTIONS=ignore_noninstrumented_modules=0:ignore_noninstrumented_modules=1 /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/deflake.bash /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/taskwait-depend.c.tmp
# executed command: tee /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/runtimes/runtimes-bins/openmp/tools/archer/tests/races/Output/taskwait-depend.c.tmp.log
# executed command: /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/build/./bin/FileCheck /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c
# .---command stderr------------
# | /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c:56:16: error: CHECK-NEXT: is not on the line after the previous match
# | // CHECK-NEXT: #0 {{.*}}taskwait-depend.c:42
# |                ^
# | <stdin>:13:2: note: 'next' match was here
# |  #0 foo /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c:42:20 (taskwait-depend.c.tmp+0x129333)
# |  ^
# | <stdin>:3:17: note: previous match ended here
# |  Write of size 4 at 0x7fffffffe2fc by thread T1:
# |                 ^
# | <stdin>:4:1: note: non-matching line after previous match is here
# |  #0 .omp_outlined..1 /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c:35:6 (taskwait-depend.c.tmp+0x12941a)
# | ^
# | 
# | Input file: <stdin>
# | Check file: /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |            1: ================== 
# |            2: WARNING: ThreadSanitizer: data race (pid=719536) 
# |            3:  Write of size 4 at 0x7fffffffe2fc by thread T1: 
# | next:56'0                    {                                   search range start (exclusive)
# |            4:  #0 .omp_outlined..1 /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c:35:6 (taskwait-depend.c.tmp+0x12941a) 
# |            5:  #1 .omp_task_entry..2 /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c:32:1 (taskwait-depend.c.tmp+0x12941a) 
# |            6:  #2 __kmp_invoke_task(int, kmp_task*, kmp_taskdata*) kmp_tasking.cpp (libomp.so+0x889be) 
# |            7:  #3 main.omp_outlined_debug__ /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c:48:19 (taskwait-depend.c.tmp+0x1294ca) 
# |            8:  #4 main.omp_outlined /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c:47:1 (taskwait-depend.c.tmp+0x1294ca) 
# |            9:  #5 __kmp_invoke_microtask <null> (libomp.so+0xeede8) 
# |           10:  #6 main /home/test-user/llvm-buildbot-worker/intel-sycl-gpu/llvm-project/openmp/tools/archer/tests/races/taskwait-depend.c:47:1 (taskwait-depend.c.tmp+0x12946f) 
# |           11:  
...

@DataCorrupted

Copy link
Copy Markdown
Member Author

Failures in openmp doesn't look related to us.

wlemkows pushed a commit to wlemkows/llvm-project that referenced this pull request Sep 4, 2026
…ral (llvm#215854)

lld determines if a `symbolName` is literal by `find_first_of("*?[]")`,
which is not accurate and ignored escape characters, we do the
following:

1. Add a new API `std::optional<std::string> asLiteral(...)` that dumps
the pattern as a literal string if it is one.
2. All `symbolNames` are considered as `GlobPattern` first to leverage
`asLeteral` to help us determine if a string is a literal. The quick
path in during `GlobPattern` construction is `if
(!S.find_first_of(PrefixMetas)) return Pat;`, so for strings without
`*?[]` (most of the `symbolName`s), the performance should be about the
same.
3. `symbolName`s that are literal go back to hashing like lld did before

Added tests in lld and unit test for GlobPattern

---------

Co-authored-by: Ellis Hoag <ellis.sparky.hoag@gmail.com>
Iasonaskrpr pushed a commit to Iasonaskrpr/llvm-project that referenced this pull request Sep 4, 2026
…ral (llvm#215854)

lld determines if a `symbolName` is literal by `find_first_of("*?[]")`,
which is not accurate and ignored escape characters, we do the
following:

1. Add a new API `std::optional<std::string> asLiteral(...)` that dumps
the pattern as a literal string if it is one.
2. All `symbolNames` are considered as `GlobPattern` first to leverage
`asLeteral` to help us determine if a string is a literal. The quick
path in during `GlobPattern` construction is `if
(!S.find_first_of(PrefixMetas)) return Pat;`, so for strings without
`*?[]` (most of the `symbolName`s), the performance should be about the
same.
3. `symbolName`s that are literal go back to hashing like lld did before

Added tests in lld and unit test for GlobPattern

---------

Co-authored-by: Ellis Hoag <ellis.sparky.hoag@gmail.com>
asudarsa-qti pushed a commit to asudarsa-qti/llvm-project that referenced this pull request Sep 4, 2026
…ral (llvm#215854)

lld determines if a `symbolName` is literal by `find_first_of("*?[]")`,
which is not accurate and ignored escape characters, we do the
following:

1. Add a new API `std::optional<std::string> asLiteral(...)` that dumps
the pattern as a literal string if it is one.
2. All `symbolNames` are considered as `GlobPattern` first to leverage
`asLeteral` to help us determine if a string is a literal. The quick
path in during `GlobPattern` construction is `if
(!S.find_first_of(PrefixMetas)) return Pat;`, so for strings without
`*?[]` (most of the `symbolName`s), the performance should be about the
same.
3. `symbolName`s that are literal go back to hashing like lld did before

Added tests in lld and unit test for GlobPattern

---------

Co-authored-by: Ellis Hoag <ellis.sparky.hoag@gmail.com>
addmisol pushed a commit to addmisol/llvm-project2 that referenced this pull request Sep 6, 2026
…ral (llvm#215854)

lld determines if a `symbolName` is literal by `find_first_of("*?[]")`,
which is not accurate and ignored escape characters, we do the
following:

1. Add a new API `std::optional<std::string> asLiteral(...)` that dumps
the pattern as a literal string if it is one.
2. All `symbolNames` are considered as `GlobPattern` first to leverage
`asLeteral` to help us determine if a string is a literal. The quick
path in during `GlobPattern` construction is `if
(!S.find_first_of(PrefixMetas)) return Pat;`, so for strings without
`*?[]` (most of the `symbolName`s), the performance should be about the
same.
3. `symbolName`s that are literal go back to hashing like lld did before

Added tests in lld and unit test for GlobPattern

---------

Co-authored-by: Ellis Hoag <ellis.sparky.hoag@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants