diff --git a/src/support/string.cpp b/src/support/string.cpp index f8f06a71804..bdb54f11f94 100644 --- a/src/support/string.cpp +++ b/src/support/string.cpp @@ -83,20 +83,66 @@ Split handleBracketingOperators(Split split) { } bool wildcardMatch(const std::string& pattern, const std::string& value) { - for (size_t i = 0; i < pattern.size(); i++) { - if (pattern[i] == '*') { - return wildcardMatch(pattern.substr(i + 1), value.substr(i)) || - (value.size() > 0 && - wildcardMatch(pattern.substr(i), value.substr(i + 1))); - } - if (i >= value.size()) { - return false; - } - if (pattern[i] != value[i]) { - return false; + size_t psize = pattern.size(), vsize = value.size(); + // When we start looking at a potential match after a wildcard, we must stash + // our current state in case we need to backtrack later. Store the positions + // in the pattern and the value. + std::vector> states; + states.emplace_back(0, 0); + while (!states.empty()) { + auto [p, v] = states.back(); + states.pop_back(); + + // Consume input until we need to backtrack. + while (true) { + // Consume matching non-wildcard input from the pattern and value. + while (p < psize && v < vsize && pattern[p] != '*' && + pattern[p] == value[v]) { + ++p; + ++v; + } + + // Handle wildcards. + if (p < psize && pattern[p] == '*') { + // Skip past the sequence of wildcards. + while (p < psize && pattern[p] == '*') { + ++p; + } + if (p == psize) { + // The pattern ended in a wildcard, so it matches the rest of the + // value no matter what it is. + return true; + } + // Find the next possible match. + while (v < vsize && value[v] != pattern[p]) { + ++v; + } + if (v == vsize) { + // No match. Backtrack if possible. + break; + } + // We do lazy matching where the wildcard consumes as little as + // possible. Try continuing the match after the wildcard from here, but + // stash the alternative state where we still have a wildcard and it has + // consumed this character in case we need to backtrack. + states.emplace_back(p - 1, v + 1); + continue; + } + + // Check end conditions. + if (p == psize && v == vsize) { + // Success! We've matched the full pattern against the full value. + return true; + } + + // We're either out of pattern or out of value or we found a mismatch, + // so we need to try to backtrack. + assert(p == psize || v == vsize || pattern[p] != value[v]); + break; } } - return value.size() == pattern.size(); + // No match, but cannot backtrack any further. + return false; } std::string trim(const std::string& input) { diff --git a/test/lit/passes/no-inline.wast b/test/lit/passes/no-inline.wast index 2e21105cb41..c59fecbb334 100644 --- a/test/lit/passes/no-inline.wast +++ b/test/lit/passes/no-inline.wast @@ -8,6 +8,7 @@ ;; RUN: foreach %s %t wasm-opt --no-partial-inline=*maybe* --inlining --optimize-level=3 --partial-inlining-ifs=1 -S -o - | filecheck %s --check-prefix NO_PART ;; RUN: foreach %s %t wasm-opt --no-full-inline=*maybe* --inlining --optimize-level=3 --partial-inlining-ifs=1 -S -o - | filecheck %s --check-prefix NO_FULL ;; RUN: foreach %s %t wasm-opt --no-inline=*maybe* --inlining --optimize-level=3 --partial-inlining-ifs=1 -S -o - | filecheck %s --check-prefix NO_BOTH +;; RUN: foreach %s %t wasm-opt --no-inline=*****maybe***** --inlining --optimize-level=3 --partial-inlining-ifs=1 -S -o - | filecheck %s --check-prefix NO_BOTH (module ;; YES_ALL: (type $0 (func)) @@ -638,6 +639,42 @@ ) ) +(func $very-long-name-we-should-not-error-on-even-though-it-is-very-very-long + ;; Test a long name. + ) + + ;; NO_FULL: (func $very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long + ;; NO_FULL-NEXT: ) + ;; NO_BOTH: (func $very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long + ;; NO_BOTH-NEXT: ) + (func $very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long + ;; Test a long name with "maybe" in it. + ) + + ;; NO_FULL: (func $very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long + ;; NO_FULL-NEXT: ) + ;; NO_BOTH: (func $very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long + ;; NO_BOTH-NEXT: ) + (func $very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long + ;; Test a long name with "maybe" in it, and a partial match earlier ("may"). + ) + +(func $maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmayb + ;; Test a long name with many partial matches but no real match. +) + +;; NO_FULL: (func $maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybe +;; NO_FULL-NEXT: ) +;; NO_BOTH: (func $maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybe +;; NO_BOTH-NEXT: ) +(func $maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybe + ;; Test a long name with many partial matches and one real match right at the end. +) + +(func $mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm + ;; Test a long name with even more tiny partial matches but no real match. +) + ;; YES_ALL: (func $caller ;; YES_ALL-NEXT: (local $0 i32) ;; YES_ALL-NEXT: (local $1 i32) @@ -741,6 +778,30 @@ ;; YES_ALL-NEXT: ) ;; YES_ALL-NEXT: ) ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: (block $__inlined_func$very-long-name-we-should-not-error-on-even-though-it-is-very-very-long$4 + ;; YES_ALL-NEXT: (block + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: (block $__inlined_func$very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long$5 + ;; YES_ALL-NEXT: (block + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: (block $__inlined_func$very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long$6 + ;; YES_ALL-NEXT: (block + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: (block $__inlined_func$maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmayb$7 + ;; YES_ALL-NEXT: (block + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: (block $__inlined_func$maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybe$8 + ;; YES_ALL-NEXT: (block + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: (block $__inlined_func$mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm$9 + ;; YES_ALL-NEXT: (block + ;; YES_ALL-NEXT: ) + ;; YES_ALL-NEXT: ) ;; YES_ALL-NEXT: ) ;; NO_PART: (func $caller ;; NO_PART-NEXT: (call $maybe-partial-or-full-1 @@ -755,6 +816,30 @@ ;; NO_PART-NEXT: (call $maybe-partial-or-full-2 ;; NO_PART-NEXT: (i32.const 1) ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: (block $__inlined_func$very-long-name-we-should-not-error-on-even-though-it-is-very-very-long + ;; NO_PART-NEXT: (block + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: (block $__inlined_func$very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long$1 + ;; NO_PART-NEXT: (block + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: (block $__inlined_func$very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long$2 + ;; NO_PART-NEXT: (block + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: (block $__inlined_func$maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmayb$3 + ;; NO_PART-NEXT: (block + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: (block $__inlined_func$maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybe$4 + ;; NO_PART-NEXT: (block + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: (block $__inlined_func$mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm$5 + ;; NO_PART-NEXT: (block + ;; NO_PART-NEXT: ) + ;; NO_PART-NEXT: ) ;; NO_PART-NEXT: ) ;; NO_FULL: (func $caller ;; NO_FULL-NEXT: (local $0 i32) @@ -817,6 +902,21 @@ ;; NO_FULL-NEXT: ) ;; NO_FULL-NEXT: ) ;; NO_FULL-NEXT: ) + ;; NO_FULL-NEXT: (block $__inlined_func$very-long-name-we-should-not-error-on-even-though-it-is-very-very-long$4 + ;; NO_FULL-NEXT: (block + ;; NO_FULL-NEXT: ) + ;; NO_FULL-NEXT: ) + ;; NO_FULL-NEXT: (call $very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long) + ;; NO_FULL-NEXT: (call $very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long) + ;; NO_FULL-NEXT: (block $__inlined_func$maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmayb$5 + ;; NO_FULL-NEXT: (block + ;; NO_FULL-NEXT: ) + ;; NO_FULL-NEXT: ) + ;; NO_FULL-NEXT: (call $maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybe) + ;; NO_FULL-NEXT: (block $__inlined_func$mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm$6 + ;; NO_FULL-NEXT: (block + ;; NO_FULL-NEXT: ) + ;; NO_FULL-NEXT: ) ;; NO_FULL-NEXT: ) ;; NO_BOTH: (func $caller ;; NO_BOTH-NEXT: (call $maybe-partial-or-full-1 @@ -831,6 +931,21 @@ ;; NO_BOTH-NEXT: (call $maybe-partial-or-full-2 ;; NO_BOTH-NEXT: (i32.const 1) ;; NO_BOTH-NEXT: ) + ;; NO_BOTH-NEXT: (block $__inlined_func$very-long-name-we-should-not-error-on-even-though-it-is-very-very-long + ;; NO_BOTH-NEXT: (block + ;; NO_BOTH-NEXT: ) + ;; NO_BOTH-NEXT: ) + ;; NO_BOTH-NEXT: (call $very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long) + ;; NO_BOTH-NEXT: (call $very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long) + ;; NO_BOTH-NEXT: (block $__inlined_func$maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmayb$1 + ;; NO_BOTH-NEXT: (block + ;; NO_BOTH-NEXT: ) + ;; NO_BOTH-NEXT: ) + ;; NO_BOTH-NEXT: (call $maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybe) + ;; NO_BOTH-NEXT: (block $__inlined_func$mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm$2 + ;; NO_BOTH-NEXT: (block + ;; NO_BOTH-NEXT: ) + ;; NO_BOTH-NEXT: ) ;; NO_BOTH-NEXT: ) (func $caller ;; In YES_ALL we will fully inline all of these. In NO_FULL we will partially @@ -851,6 +966,12 @@ (call $maybe-partial-or-full-2 (i32.const 1) ) + (call $very-long-name-we-should-not-error-on-even-though-it-is-very-very-long) + (call $very-long-name-we-should-not-error-on-maybe-even-though-it-is-very-very-long) + (call $very-long-name-we-may-should-not-error-on-maybe-even-though-it-is-very-very-long) + (call $maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmayb) + (call $maybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybmaybe) + (call $mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm) ) ) ;; NO_FULL: (func $byn-split-outlined-B$maybe-partial-or-full-1 (param $x i32)