Update external c libs: SFMT & peglib (#6901)

This commit is contained in:
tooomm 2026-05-22 03:31:59 +02:00 committed by GitHub
parent a9003be30f
commit 74102aa1ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 80 additions and 18 deletions

View file

@ -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"

View file

@ -88,8 +88,13 @@ union W128_T {
uint64_t u64[2];
uint32x4_t si;
};
//#elif defined(HAVE_SSE2)
#elif defined(HAVE_SSE2)
#include <emmintrin.h>
#if defined(__AVX2__)
#include <immintrin.h>
#else
#include <emmintrin.h>
#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)

View file

@ -37,6 +37,7 @@
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#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<const Definition *, FirstSet>;
explicit ComputeFirstSet(FirstSetCache &cache) : cache_(cache) {}
FirstSet result_;
private:
std::unordered_set<std::string> refs_;
FirstSetCache &cache_;
std::unordered_set<const Definition *> 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<std::string> refs_;
ComputeFirstSet::FirstSetCache first_set_cache_;
std::unordered_set<const Definition *> 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) {