mirror of
https://github.com/VectorCamp/vectorscan.git
synced 2025-06-28 16:41:01 +03:00
rose_build_groups: move assignGroupsToLiterals
This commit is contained in:
parent
c2496fbf76
commit
2b24000b1a
@ -69,7 +69,6 @@
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -78,41 +77,16 @@
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
|
||||
using namespace std;
|
||||
using boost::adaptors::map_keys;
|
||||
using boost::adaptors::map_values;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
#define ROSE_LONG_LITERAL_LEN 8
|
||||
|
||||
#define ANCHORED_REHOME_MIN_FLOATING 800
|
||||
#define ANCHORED_REHOME_MIN_FLOATING_SHORT 50
|
||||
#define ANCHORED_REHOME_ALLOW_SHORT 20
|
||||
#define ANCHORED_REHOME_DEEP 25
|
||||
#define ANCHORED_REHOME_SHORT_LEN 3
|
||||
|
||||
static
|
||||
bool superStrong(const rose_literal_id &lit) {
|
||||
if (lit.s.length() < ROSE_LONG_LITERAL_LEN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 EXPECTED_FDR_BUCKET_LENGTH = 8;
|
||||
|
||||
assert(lit.s.length() >= EXPECTED_FDR_BUCKET_LENGTH);
|
||||
size_t len = lit.s.length();
|
||||
const string &s = lit.s.get_string();
|
||||
|
||||
for (size_t i = 1; i < EXPECTED_FDR_BUCKET_LENGTH; i++) {
|
||||
if (s[len - 1 - i] != s[len - 1]) {
|
||||
return true; /* we have at least some variation in the tail */
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTF("lit '%s' is not superstrong due to tail\n",
|
||||
escapeString(s).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
rose_group RoseBuildImpl::getGroups(RoseVertex v) const {
|
||||
rose_group groups = 0;
|
||||
|
||||
@ -863,274 +837,6 @@ bool RoseBuildImpl::hasFinalId(u32 id) const {
|
||||
return literal_info.at(id).final_id != MO_INVALID_IDX;
|
||||
}
|
||||
|
||||
static
|
||||
bool eligibleForAlwaysOnGroup(const RoseBuildImpl &tbi, u32 id) {
|
||||
/* returns true if it or any of its delay versions have root role */
|
||||
for (auto v : tbi.literal_info[id].vertices) {
|
||||
if (tbi.isRootSuccessor(v)) {
|
||||
NGHolder *h = tbi.g[v].left.graph.get();
|
||||
if (!h || proper_out_degree(h->startDs, *h)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 delayed_id : tbi.literal_info[id].delayed_ids) {
|
||||
for (auto v : tbi.literal_info[delayed_id].vertices) {
|
||||
if (tbi.isRootSuccessor(v)) {
|
||||
NGHolder *h = tbi.g[v].left.graph.get();
|
||||
if (!h || proper_out_degree(h->startDs, *h)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static
|
||||
bool requires_group_assignment(const rose_literal_id &lit,
|
||||
const rose_literal_info &info) {
|
||||
if (lit.delay) { /* we will check the shadow's master */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lit.table == ROSE_ANCHORED || lit.table == ROSE_EVENT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we already have a group applied, skip.
|
||||
if (info.group_mask) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.vertices.empty() && info.delayed_ids.empty()) {
|
||||
DEBUG_PRINTF("literal is good for nothing\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
rose_group calcLocalGroup(const RoseVertex v, const RoseGraph &g,
|
||||
const deque<rose_literal_info> &literal_info,
|
||||
const bool small_literal_count) {
|
||||
rose_group local_group = 0;
|
||||
|
||||
for (auto u : inv_adjacent_vertices_range(v, g)) {
|
||||
/* In small cases, ensure that siblings have the same rose parentage to
|
||||
* allow rose squashing. In larger cases, don't do this as groups are
|
||||
* probably too scarce. */
|
||||
for (auto w : adjacent_vertices_range(u, g)) {
|
||||
if (!small_literal_count || g[v].left == g[w].left) {
|
||||
for (u32 lit_id : g[w].literals) {
|
||||
local_group |= literal_info[lit_id].group_mask;
|
||||
}
|
||||
} else {
|
||||
DEBUG_PRINTF("not sibling different mother %zu %zu\n",
|
||||
g[v].idx, g[w].idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return local_group;
|
||||
}
|
||||
|
||||
/* group constants */
|
||||
#define MAX_LIGHT_LITERAL_CASE 200 /* allow rose to affect group decisions below
|
||||
* this */
|
||||
|
||||
static
|
||||
flat_set<RoseVertex> getAssociatedVertices(const RoseBuildImpl &build, u32 id) {
|
||||
flat_set<RoseVertex> out;
|
||||
const auto &info = build.literal_info[id];
|
||||
insert(&out, info.vertices);
|
||||
for (const auto &delayed : info.delayed_ids) {
|
||||
insert(&out, build.literal_info[delayed].vertices);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static
|
||||
u32 next_available_group(u32 counter, u32 min_start_group) {
|
||||
counter++;
|
||||
if (counter == ROSE_GROUPS_MAX) {
|
||||
DEBUG_PRINTF("resetting groups\n");
|
||||
counter = min_start_group;
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
// Assigns groups to literals in the general case, when we have more literals
|
||||
// than available groups.
|
||||
void RoseBuildImpl::assignGroupsToLiterals() {
|
||||
bool small_literal_count = literal_info.size() <= MAX_LIGHT_LITERAL_CASE;
|
||||
|
||||
map<u8, u32> groupCount; /* group index to number of members */
|
||||
|
||||
u32 counter = 0;
|
||||
u32 group_always_on = 0;
|
||||
|
||||
// First pass: handle always on literals.
|
||||
for (const auto &e : literals.right) {
|
||||
u32 id = e.first;
|
||||
const rose_literal_id &lit = e.second;
|
||||
rose_literal_info &info = literal_info[id];
|
||||
|
||||
if (!requires_group_assignment(lit, info)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this literal has a root role, we always have to search for it
|
||||
// anyway, so it goes in the always-on group.
|
||||
/* We could end up squashing it if it is followed by a .* */
|
||||
if (eligibleForAlwaysOnGroup(*this, id)) {
|
||||
info.group_mask = 1ULL << group_always_on;
|
||||
groupCount[group_always_on]++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
u32 group_long_lit;
|
||||
if (groupCount[group_always_on]) {
|
||||
DEBUG_PRINTF("%u always on literals\n", groupCount[group_always_on]);
|
||||
group_long_lit = group_always_on;
|
||||
counter++;
|
||||
} else {
|
||||
group_long_lit = counter;
|
||||
counter++;
|
||||
}
|
||||
|
||||
u32 min_start_group = counter;
|
||||
priority_queue<pair<pair<s32, s32>, u32> > pq;
|
||||
|
||||
// Second pass: the other literals.
|
||||
for (const auto &e : literals.right) {
|
||||
u32 id = e.first;
|
||||
const rose_literal_id &lit = e.second;
|
||||
rose_literal_info &info = literal_info[id];
|
||||
|
||||
if (!requires_group_assignment(lit, info)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(!eligibleForAlwaysOnGroup(*this, id));
|
||||
pq.push(make_pair(make_pair(-(s32)literal_info[id].vertices.size(),
|
||||
-(s32)lit.s.length()), id));
|
||||
}
|
||||
|
||||
vector<u32> long_lits;
|
||||
while (!pq.empty()) {
|
||||
u32 id = pq.top().second;
|
||||
pq.pop();
|
||||
UNUSED const rose_literal_id &lit = literals.right.at(id);
|
||||
DEBUG_PRINTF("assigning groups to lit %u (v %zu l %zu)\n", id,
|
||||
literal_info[id].vertices.size(), lit.s.length());
|
||||
|
||||
u8 group_id = 0;
|
||||
rose_group group = ~0ULL;
|
||||
for (auto v : getAssociatedVertices(*this, id)) {
|
||||
rose_group local_group = calcLocalGroup(v, g, literal_info,
|
||||
small_literal_count);
|
||||
group &= local_group;
|
||||
if (!group) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (group == ~0ULL) {
|
||||
goto boring;
|
||||
}
|
||||
|
||||
group &= ~((1ULL << min_start_group) - 1); /* ensure the purity of the
|
||||
* always_on groups */
|
||||
if (!group) {
|
||||
goto boring;
|
||||
}
|
||||
|
||||
group_id = ctz64(group);
|
||||
|
||||
/* TODO: fairness */
|
||||
DEBUG_PRINTF("picking sibling group %hhd\n", group_id);
|
||||
literal_info[id].group_mask = 1ULL << group_id;
|
||||
groupCount[group_id]++;
|
||||
|
||||
continue;
|
||||
|
||||
boring:
|
||||
/* long literals will either be stuck in a mega group or spread around
|
||||
* depending on availability */
|
||||
if (superStrong(lit)) {
|
||||
long_lits.push_back(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Other literals are assigned to our remaining groups round-robin.
|
||||
group_id = counter;
|
||||
|
||||
DEBUG_PRINTF("picking boring group %hhd\n", group_id);
|
||||
literal_info[id].group_mask = 1ULL << group_id;
|
||||
groupCount[group_id]++;
|
||||
counter = next_available_group(counter, min_start_group);
|
||||
}
|
||||
|
||||
/* spread long literals out amongst unused groups if any, otherwise stick
|
||||
* them in the always on the group */
|
||||
|
||||
if (groupCount[counter]) {
|
||||
DEBUG_PRINTF("sticking long literals in the image of the always on\n");
|
||||
for (u32 lit_id : long_lits) {
|
||||
literal_info[lit_id].group_mask = 1ULL << group_long_lit;
|
||||
groupCount[group_long_lit]++;
|
||||
}
|
||||
} else {
|
||||
u32 min_long_counter = counter;
|
||||
DEBUG_PRINTF("base long lit group = %u\n", min_long_counter);
|
||||
for (u32 lit_id : long_lits) {
|
||||
u8 group_id = counter;
|
||||
literal_info[lit_id].group_mask = 1ULL << group_id;
|
||||
groupCount[group_id]++;
|
||||
counter = next_available_group(counter, min_long_counter);
|
||||
}
|
||||
}
|
||||
|
||||
/* assign delayed literals to the same group as their parent */
|
||||
for (const auto &e : literals.right) {
|
||||
u32 id = e.first;
|
||||
const rose_literal_id &lit = e.second;
|
||||
|
||||
if (!lit.delay) {
|
||||
continue;
|
||||
}
|
||||
|
||||
u32 parent = literal_info[id].undelayed_id;
|
||||
DEBUG_PRINTF("%u is shadow picking up groups from %u\n", id, parent);
|
||||
assert(literal_info[parent].undelayed_id == parent);
|
||||
assert(literal_info[parent].group_mask);
|
||||
literal_info[id].group_mask = literal_info[parent].group_mask;
|
||||
/* don't increment the group count - these don't really exist */
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("populate group to literal mapping\n");
|
||||
for (const u32 id : literals.right | map_keys) {
|
||||
rose_group groups = literal_info[id].group_mask;
|
||||
while (groups) {
|
||||
u32 group_id = findAndClearLSB_64(&groups);
|
||||
group_to_literal[group_id].insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
/* find how many groups we allocated */
|
||||
for (u32 i = 0; i < ROSE_GROUPS_MAX; i++) {
|
||||
if (groupCount[i]) {
|
||||
group_end = MAX(group_end, i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RoseBuildImpl::hasDelayedLiteral(RoseVertex v) const {
|
||||
for (u32 lit_id : g[v].literals) {
|
||||
if (literals.right.at(lit_id).delay) {
|
||||
|
@ -33,15 +33,308 @@
|
||||
|
||||
#include "rose_build_groups.h"
|
||||
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/graph/topological_sort.hpp>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
|
||||
using namespace std;
|
||||
using boost::adaptors::map_keys;
|
||||
|
||||
namespace ue2 {
|
||||
|
||||
#define ROSE_LONG_LITERAL_LEN 8
|
||||
|
||||
static
|
||||
bool superStrong(const rose_literal_id &lit) {
|
||||
if (lit.s.length() < ROSE_LONG_LITERAL_LEN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 EXPECTED_FDR_BUCKET_LENGTH = 8;
|
||||
|
||||
assert(lit.s.length() >= EXPECTED_FDR_BUCKET_LENGTH);
|
||||
size_t len = lit.s.length();
|
||||
const string &s = lit.s.get_string();
|
||||
|
||||
for (size_t i = 1; i < EXPECTED_FDR_BUCKET_LENGTH; i++) {
|
||||
if (s[len - 1 - i] != s[len - 1]) {
|
||||
return true; /* we have at least some variation in the tail */
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTF("lit '%s' is not superstrong due to tail\n",
|
||||
escapeString(s).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
static
|
||||
bool eligibleForAlwaysOnGroup(const RoseBuildImpl &build, u32 id) {
|
||||
/* returns true if it or any of its delay versions have root role */
|
||||
for (auto v : build.literal_info[id].vertices) {
|
||||
if (build.isRootSuccessor(v)) {
|
||||
NGHolder *h = build.g[v].left.graph.get();
|
||||
if (!h || proper_out_degree(h->startDs, *h)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 delayed_id : build.literal_info[id].delayed_ids) {
|
||||
for (auto v : build.literal_info[delayed_id].vertices) {
|
||||
if (build.isRootSuccessor(v)) {
|
||||
NGHolder *h = build.g[v].left.graph.get();
|
||||
if (!h || proper_out_degree(h->startDs, *h)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static
|
||||
bool requires_group_assignment(const rose_literal_id &lit,
|
||||
const rose_literal_info &info) {
|
||||
if (lit.delay) { /* we will check the shadow's master */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lit.table == ROSE_ANCHORED || lit.table == ROSE_EVENT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we already have a group applied, skip.
|
||||
if (info.group_mask) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.vertices.empty() && info.delayed_ids.empty()) {
|
||||
DEBUG_PRINTF("literal is good for nothing\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
rose_group calcLocalGroup(const RoseVertex v, const RoseGraph &g,
|
||||
const deque<rose_literal_info> &literal_info,
|
||||
const bool small_literal_count) {
|
||||
rose_group local_group = 0;
|
||||
|
||||
for (auto u : inv_adjacent_vertices_range(v, g)) {
|
||||
/* In small cases, ensure that siblings have the same rose parentage to
|
||||
* allow rose squashing. In larger cases, don't do this as groups are
|
||||
* probably too scarce. */
|
||||
for (auto w : adjacent_vertices_range(u, g)) {
|
||||
if (!small_literal_count || g[v].left == g[w].left) {
|
||||
for (u32 lit_id : g[w].literals) {
|
||||
local_group |= literal_info[lit_id].group_mask;
|
||||
}
|
||||
} else {
|
||||
DEBUG_PRINTF("not sibling different mother %zu %zu\n",
|
||||
g[v].idx, g[w].idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return local_group;
|
||||
}
|
||||
|
||||
/* group constants */
|
||||
#define MAX_LIGHT_LITERAL_CASE 200 /* allow rose to affect group decisions below
|
||||
* this */
|
||||
|
||||
static
|
||||
flat_set<RoseVertex> getAssociatedVertices(const RoseBuildImpl &build, u32 id) {
|
||||
flat_set<RoseVertex> out;
|
||||
const auto &info = build.literal_info[id];
|
||||
insert(&out, info.vertices);
|
||||
for (const auto &delayed : info.delayed_ids) {
|
||||
insert(&out, build.literal_info[delayed].vertices);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static
|
||||
u32 next_available_group(u32 counter, u32 min_start_group) {
|
||||
counter++;
|
||||
if (counter == ROSE_GROUPS_MAX) {
|
||||
DEBUG_PRINTF("resetting groups\n");
|
||||
counter = min_start_group;
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
// Assigns groups to literals in the general case, when we have more literals
|
||||
// than available groups.
|
||||
void RoseBuildImpl::assignGroupsToLiterals() {
|
||||
bool small_literal_count = literal_info.size() <= MAX_LIGHT_LITERAL_CASE;
|
||||
|
||||
map<u8, u32> groupCount; /* group index to number of members */
|
||||
|
||||
u32 counter = 0;
|
||||
u32 group_always_on = 0;
|
||||
|
||||
// First pass: handle always on literals.
|
||||
for (const auto &e : literals.right) {
|
||||
u32 id = e.first;
|
||||
const rose_literal_id &lit = e.second;
|
||||
rose_literal_info &info = literal_info[id];
|
||||
|
||||
if (!requires_group_assignment(lit, info)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this literal has a root role, we always have to search for it
|
||||
// anyway, so it goes in the always-on group.
|
||||
/* We could end up squashing it if it is followed by a .* */
|
||||
if (eligibleForAlwaysOnGroup(*this, id)) {
|
||||
info.group_mask = 1ULL << group_always_on;
|
||||
groupCount[group_always_on]++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
u32 group_long_lit;
|
||||
if (groupCount[group_always_on]) {
|
||||
DEBUG_PRINTF("%u always on literals\n", groupCount[group_always_on]);
|
||||
group_long_lit = group_always_on;
|
||||
counter++;
|
||||
} else {
|
||||
group_long_lit = counter;
|
||||
counter++;
|
||||
}
|
||||
|
||||
u32 min_start_group = counter;
|
||||
priority_queue<pair<pair<s32, s32>, u32> > pq;
|
||||
|
||||
// Second pass: the other literals.
|
||||
for (const auto &e : literals.right) {
|
||||
u32 id = e.first;
|
||||
const rose_literal_id &lit = e.second;
|
||||
rose_literal_info &info = literal_info[id];
|
||||
|
||||
if (!requires_group_assignment(lit, info)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(!eligibleForAlwaysOnGroup(*this, id));
|
||||
pq.push(make_pair(make_pair(-(s32)literal_info[id].vertices.size(),
|
||||
-(s32)lit.s.length()), id));
|
||||
}
|
||||
vector<u32> long_lits;
|
||||
while (!pq.empty()) {
|
||||
u32 id = pq.top().second;
|
||||
pq.pop();
|
||||
UNUSED const rose_literal_id &lit = literals.right.at(id);
|
||||
DEBUG_PRINTF("assigning groups to lit %u (v %zu l %zu)\n", id,
|
||||
literal_info[id].vertices.size(), lit.s.length());
|
||||
|
||||
u8 group_id = 0;
|
||||
rose_group group = ~0ULL;
|
||||
for (auto v : getAssociatedVertices(*this, id)) {
|
||||
rose_group local_group = calcLocalGroup(v, g, literal_info,
|
||||
small_literal_count);
|
||||
group &= local_group;
|
||||
if (!group) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (group == ~0ULL) {
|
||||
goto boring;
|
||||
}
|
||||
|
||||
group &= ~((1ULL << min_start_group) - 1); /* ensure the purity of the
|
||||
* always_on groups */
|
||||
if (!group) {
|
||||
goto boring;
|
||||
}
|
||||
|
||||
group_id = ctz64(group);
|
||||
|
||||
/* TODO: fairness */
|
||||
DEBUG_PRINTF("picking sibling group %hhd\n", group_id);
|
||||
literal_info[id].group_mask = 1ULL << group_id;
|
||||
groupCount[group_id]++;
|
||||
|
||||
continue;
|
||||
|
||||
boring:
|
||||
/* long literals will either be stuck in a mega group or spread around
|
||||
* depending on availability */
|
||||
if (superStrong(lit)) {
|
||||
long_lits.push_back(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Other literals are assigned to our remaining groups round-robin.
|
||||
group_id = counter;
|
||||
|
||||
DEBUG_PRINTF("picking boring group %hhd\n", group_id);
|
||||
literal_info[id].group_mask = 1ULL << group_id;
|
||||
groupCount[group_id]++;
|
||||
counter = next_available_group(counter, min_start_group);
|
||||
}
|
||||
|
||||
/* spread long literals out amongst unused groups if any, otherwise stick
|
||||
* them in the always on the group */
|
||||
|
||||
if (groupCount[counter]) {
|
||||
DEBUG_PRINTF("sticking long literals in the image of the always on\n");
|
||||
for (u32 lit_id : long_lits) {
|
||||
literal_info[lit_id].group_mask = 1ULL << group_long_lit;
|
||||
groupCount[group_long_lit]++;
|
||||
}
|
||||
} else {
|
||||
u32 min_long_counter = counter;
|
||||
DEBUG_PRINTF("base long lit group = %u\n", min_long_counter);
|
||||
for (u32 lit_id : long_lits) {
|
||||
u8 group_id = counter;
|
||||
literal_info[lit_id].group_mask = 1ULL << group_id;
|
||||
groupCount[group_id]++;
|
||||
counter = next_available_group(counter, min_long_counter);
|
||||
}
|
||||
}
|
||||
/* assign delayed literals to the same group as their parent */
|
||||
for (const auto &e : literals.right) {
|
||||
u32 id = e.first;
|
||||
const rose_literal_id &lit = e.second;
|
||||
|
||||
if (!lit.delay) {
|
||||
continue;
|
||||
}
|
||||
|
||||
u32 parent = literal_info[id].undelayed_id;
|
||||
DEBUG_PRINTF("%u is shadow picking up groups from %u\n", id, parent);
|
||||
assert(literal_info[parent].undelayed_id == parent);
|
||||
assert(literal_info[parent].group_mask);
|
||||
literal_info[id].group_mask = literal_info[parent].group_mask;
|
||||
/* don't increment the group count - these don't really exist */
|
||||
}
|
||||
|
||||
DEBUG_PRINTF("populate group to literal mapping\n");
|
||||
for (const u32 id : literals.right | map_keys) {
|
||||
rose_group groups = literal_info[id].group_mask;
|
||||
while (groups) {
|
||||
u32 group_id = findAndClearLSB_64(&groups);
|
||||
group_to_literal[group_id].insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
/* find how many groups we allocated */
|
||||
for (u32 i = 0; i < ROSE_GROUPS_MAX; i++) {
|
||||
if (groupCount[i]) {
|
||||
group_end = MAX(group_end, i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns a mapping from each graph vertex v to the intersection of the
|
||||
* groups switched on by all of the paths leading up to (and including) v from
|
||||
|
Loading…
x
Reference in New Issue
Block a user