From 74102aa1ec05381b96fadedeb05a18891b852658 Mon Sep 17 00:00:00 2001 From: tooomm Date: Fri, 22 May 2026 03:31:59 +0200 Subject: [PATCH] Update external c libs: SFMT & peglib (#6901) --- .../libcockatrice/rng/sfmt/SFMT.c | 4 +- .../libcockatrice/rng/sfmt/SFMT.h | 21 +++++- .../libcockatrice/utility/peglib.h | 73 +++++++++++++++---- 3 files changed, 80 insertions(+), 18 deletions(-) diff --git a/libcockatrice_rng/libcockatrice/rng/sfmt/SFMT.c b/libcockatrice_rng/libcockatrice/rng/sfmt/SFMT.c index b4ac9308b..fde6367a0 100644 --- a/libcockatrice_rng/libcockatrice/rng/sfmt/SFMT.c +++ b/libcockatrice_rng/libcockatrice/rng/sfmt/SFMT.c @@ -60,7 +60,9 @@ inline static void swap(w128_t *array, int size); */ static const w128_t sse2_param_mask = {{SFMT_MSK1, SFMT_MSK2, SFMT_MSK3, SFMT_MSK4}}; - #if defined(_MSC_VER) + #if defined(__AVX2__) && (SFMT_SL1 >= 16) && !(SFMT_N & 1) && !(SFMT_POS1 & 1) + #include "SFMT-avx256.h" + #elif defined(_MSC_VER) #include "SFMT-sse2-msc.h" #else #include "SFMT-sse2.h" diff --git a/libcockatrice_rng/libcockatrice/rng/sfmt/SFMT.h b/libcockatrice_rng/libcockatrice/rng/sfmt/SFMT.h index 79e012d63..34d9e746f 100644 --- a/libcockatrice_rng/libcockatrice/rng/sfmt/SFMT.h +++ b/libcockatrice_rng/libcockatrice/rng/sfmt/SFMT.h @@ -88,8 +88,13 @@ union W128_T { uint64_t u64[2]; uint32x4_t si; }; +//#elif defined(HAVE_SSE2) #elif defined(HAVE_SSE2) - #include + #if defined(__AVX2__) + #include + #else + #include + #endif /** 128-bit data structure */ union W128_T { @@ -112,8 +117,18 @@ typedef union W128_T w128_t; * SFMT internal state */ struct SFMT_T { +#if defined(__AVX2__) + union { + w128_t state[SFMT_N]; + __m256i state_ymm[SFMT_N/2]; + #if defined(__AVX512VL__) + __m512i state_zmm[SFMT_N/4]; + #endif + }; +#else /** the 128-bit internal state array */ w128_t state[SFMT_N]; +#endif /** index counter to the 32-bit internal state array */ int idx; }; @@ -249,9 +264,9 @@ inline static double sfmt_genrand_real3(sfmt_t * sfmt) } /** - * converts an unsigned 32-bit integer to double on [0,1) + * converts an unsigned 64-bit integer to double on [0,1) * with 53-bit resolution. - * @param v 32-bit unsigned integer + * @param v 64-bit unsigned integer * @return double on [0,1)-real-interval with 53-bit resolution. */ inline static double sfmt_to_res53(uint64_t v) diff --git a/libcockatrice_utility/libcockatrice/utility/peglib.h b/libcockatrice_utility/libcockatrice/utility/peglib.h index 3ae6040c4..e7e558dff 100644 --- a/libcockatrice_utility/libcockatrice/utility/peglib.h +++ b/libcockatrice_utility/libcockatrice/utility/peglib.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #if !defined(__cplusplus) || __cplusplus < 201703L @@ -505,7 +506,7 @@ inline constexpr unsigned int str2tag(std::string_view sv) { namespace udl { -inline constexpr unsigned int operator""_(const char *s, size_t l) { +inline constexpr unsigned int operator"" _(const char *s, size_t l) { return str2tag_core(s, l, 0); } @@ -2434,10 +2435,11 @@ struct ComputeFirstSet : public TraversalVisitor { void visit(Sequence &ope) override { for (const auto &op : ope.opes_) { + FirstSet element_fs; auto save = result_; result_ = FirstSet{}; op->accept(*this); - auto element_fs = result_; + element_fs = result_; result_ = save; result_.chars |= element_fs.chars; if (element_fs.any_char) { result_.any_char = true; } @@ -2526,10 +2528,22 @@ struct ComputeFirstSet : public TraversalVisitor { void visit(BackReference &) override { result_.any_char = true; } void visit(Cut &) override { result_.can_be_empty = true; } + // Per-rule cache shared across a SetupFirstSets traversal. Without it, + // every alternative of every PrioritizedChoice re-walks referenced + // rules — O(refs^depth) work for grammars with many cross-references. + // Only cycle-free rule computations are cached; results computed under + // a cycle (left recursion) would be incomplete and unsafe to reuse from + // a different call context. + using FirstSetCache = std::unordered_map; + + explicit ComputeFirstSet(FirstSetCache &cache) : cache_(cache) {} + FirstSet result_; private: - std::unordered_set refs_; + FirstSetCache &cache_; + std::unordered_set refs_; + size_t cycle_count_ = 0; }; struct SetupFirstSets : public TraversalVisitor { @@ -2542,7 +2556,7 @@ struct SetupFirstSets : public TraversalVisitor { ope.first_sets_.clear(); ope.first_sets_.reserve(ope.opes_.size()); for (const auto &op : ope.opes_) { - ComputeFirstSet cfs; + ComputeFirstSet cfs(first_set_cache_); op->accept(cfs); ope.first_sets_.push_back(cfs.result_); } @@ -2559,7 +2573,8 @@ struct SetupFirstSets : public TraversalVisitor { void visit(Reference &ope) override; private: - std::unordered_set refs_; + ComputeFirstSet::FirstSetCache first_set_cache_; + std::unordered_set visited_rules_; }; /* @@ -3806,20 +3821,50 @@ inline void ComputeFirstSet::visit(Reference &ope) { result_.any_char = true; return; } - if (refs_.count(ope.name_)) { return; } - refs_.insert(ope.name_); - ope.rule_->accept(*this); - if (!result_.first_rule && ope.rule_->is_token()) { - result_.first_rule = ope.rule_; + + auto it = cache_.find(ope.rule_); + FirstSet computed; + const FirstSet *rule_fs; + if (it != cache_.end()) { + rule_fs = &it->second; + } else { + if (!refs_.insert(ope.rule_).second) { + cycle_count_++; // cycle / left recursion + return; + } + auto save = std::exchange(result_, FirstSet{}); + auto saved_cycle_count = cycle_count_; + ope.rule_->accept(*this); + computed = std::move(result_); + result_ = std::move(save); + refs_.erase(ope.rule_); + if (cycle_count_ == saved_cycle_count) { + // Cycle-free: cached value is complete and safe to reuse. + it = cache_.try_emplace(ope.rule_, std::move(computed)).first; + rule_fs = &it->second; + } else { + // Cycle was hit during this rule's computation — its result may be + // missing contributions from rules that were on the call stack. + // Use the value here but do not cache it for other call contexts. + rule_fs = &computed; + } + } + + result_.merge(*rule_fs); + if (!result_.first_literal) { + result_.first_literal = rule_fs->first_literal; + } + if (!result_.first_rule) { + result_.first_rule = rule_fs->first_rule + ? rule_fs->first_rule + : (ope.rule_->is_token() ? ope.rule_ : nullptr); } - refs_.erase(ope.name_); } inline void SetupFirstSets::visit(Reference &ope) { - if (!ope.rule_ || refs_.count(ope.name_)) { return; } - refs_.insert(ope.name_); + if (!ope.rule_) { return; } + if (!visited_rules_.insert(ope.rule_).second) { return; } ope.rule_->accept(*this); - refs_.erase(ope.name_); } inline void SetupFirstSets::visit(Sequence &ope) {