mirror of
https://github.com/VectorCamp/vectorscan.git
synced 2025-06-28 16:41:01 +03:00
refactor mergeCastleLeftfixes
This commit is contained in:
parent
cee0b722a3
commit
6f452668ec
@ -84,6 +84,7 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using boost::adaptors::map_values;
|
using boost::adaptors::map_values;
|
||||||
|
using boost::adaptors::map_keys;
|
||||||
|
|
||||||
namespace ue2 {
|
namespace ue2 {
|
||||||
|
|
||||||
@ -1037,8 +1038,18 @@ bool mergeLeftfixPair(RoseBuildImpl &build, left_id &r1, left_id &r2,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that there is no problem due to the involved vertices if we merge two
|
||||||
|
* leftfix engines.
|
||||||
|
*
|
||||||
|
* This functions takes the vertices on the right of the two engines.
|
||||||
|
*
|
||||||
|
* Unlike mergeableRoseVertices(), this does not:
|
||||||
|
* - check that engines themselves can be merged
|
||||||
|
* - use heuristics to find out if merging the engines is wise.
|
||||||
|
*/
|
||||||
static
|
static
|
||||||
bool mergeLeftVL_checkTargetsCompatible(const RoseBuildImpl &build,
|
bool checkVerticesOkForLeftfixMerge(const RoseBuildImpl &build,
|
||||||
const vector<RoseVertex> &targets_1,
|
const vector<RoseVertex> &targets_1,
|
||||||
const vector<RoseVertex> &targets_2) {
|
const vector<RoseVertex> &targets_2) {
|
||||||
assert(!targets_1.empty());
|
assert(!targets_1.empty());
|
||||||
@ -1206,7 +1217,7 @@ bool mergeLeftVL_tryMergeCandidate(RoseBuildImpl &build, left_id &r1,
|
|||||||
/* Rechecking that the targets are compatible, as we may have already
|
/* Rechecking that the targets are compatible, as we may have already
|
||||||
* merged new states into r1 or r2 and we need to verify that this
|
* merged new states into r1 or r2 and we need to verify that this
|
||||||
* candidate is still ok. */
|
* candidate is still ok. */
|
||||||
if (!mergeLeftVL_checkTargetsCompatible(build, targets_1, targets_2)) {
|
if (!checkVerticesOkForLeftfixMerge(build, targets_1, targets_2)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1460,7 +1471,7 @@ void mergeLeftfixesVariableLag(RoseBuildImpl &build) {
|
|||||||
|| r1.castle()->reach() == r2.castle()->reach());
|
|| r1.castle()->reach() == r2.castle()->reach());
|
||||||
|
|
||||||
const vector<RoseVertex> &targets_2 = eng_verts[r2];
|
const vector<RoseVertex> &targets_2 = eng_verts[r2];
|
||||||
if (!mergeLeftVL_checkTargetsCompatible(build, targets_1,
|
if (!checkVerticesOkForLeftfixMerge(build, targets_1,
|
||||||
targets_2)) {
|
targets_2)) {
|
||||||
continue; // No point queueing unmergeable cases.
|
continue; // No point queueing unmergeable cases.
|
||||||
}
|
}
|
||||||
@ -1847,66 +1858,6 @@ void mergeNfaLeftfixes(RoseBuildImpl &tbi, RoseBouquet &roses) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
void mergeCastleChunk(RoseBuildImpl &tbi, RoseBouquet &cands) {
|
|
||||||
/* caller must have already ensured that candidates have the same reach */
|
|
||||||
RoseGraph &g = tbi.g;
|
|
||||||
DEBUG_PRINTF("%zu castle rose merge candidates\n", cands.size());
|
|
||||||
|
|
||||||
deque<left_id> merged;
|
|
||||||
|
|
||||||
for (auto it = cands.begin(); it != cands.end(); ++it) {
|
|
||||||
left_id r1 = *it;
|
|
||||||
CastleProto &castle1 = *r1.castle();
|
|
||||||
const deque<RoseVertex> &verts1 = cands.vertices(r1);
|
|
||||||
|
|
||||||
merged.clear();
|
|
||||||
|
|
||||||
for (auto jt = next(it); jt != cands.end(); ++jt) {
|
|
||||||
left_id r2 = *jt;
|
|
||||||
CastleProto &castle2 = *r2.castle();
|
|
||||||
const deque<RoseVertex> &verts2 = cands.vertices(r2);
|
|
||||||
|
|
||||||
if (castle1.repeats.size() == castle1.max_occupancy) {
|
|
||||||
DEBUG_PRINTF("castle1 has hit max occupancy\n");
|
|
||||||
break; // next castle1
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(castle1.reach() == castle2.reach());
|
|
||||||
|
|
||||||
if (!mergeableRoseVertices(tbi, verts1, verts2)) {
|
|
||||||
DEBUG_PRINTF("not mergeable\n");
|
|
||||||
continue; // next castle2
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_PRINTF("castle1=%p (size %zu), castle2=%p (size %zu)\n",
|
|
||||||
&castle1, castle1.repeats.size(), &castle2,
|
|
||||||
castle2.repeats.size());
|
|
||||||
|
|
||||||
map<u32, u32> top_map;
|
|
||||||
if (!mergeCastle(castle1, castle2, top_map)) {
|
|
||||||
DEBUG_PRINTF("couldn't merge\n");
|
|
||||||
continue; // next castle2
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update castle2's roses to point to castle1 now.
|
|
||||||
shared_ptr<CastleProto> winner = g[verts1.front()].left.castle;
|
|
||||||
for (auto v : verts2) {
|
|
||||||
g[v].left.castle = winner;
|
|
||||||
for (const auto &e : in_edges_range(v, g)) {
|
|
||||||
g[e].rose_top = top_map.at(g[e].rose_top);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cands.insert(r1, verts2);
|
|
||||||
merged.push_back(r2);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_PRINTF("%zu roses merged\n", merged.size());
|
|
||||||
cands.erase_all(merged.begin(), merged.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This pass attempts to merge prefix/infix engines with a small number of
|
* This pass attempts to merge prefix/infix engines with a small number of
|
||||||
* vertices together into larger engines. The engines must not be have a
|
* vertices together into larger engines. The engines must not be have a
|
||||||
@ -1983,55 +1934,110 @@ void mergeSmallLeftfixes(RoseBuildImpl &tbi) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mergeCastleLeftfixes(RoseBuildImpl &tbi) {
|
|
||||||
|
static
|
||||||
|
void mergeCastleChunk(RoseBuildImpl &build, vector<left_id> &cands,
|
||||||
|
insertion_ordered_map<left_id, vector<RoseVertex>> &eng_verts) {
|
||||||
|
/* caller must have already ensured that candidates have the same reach */
|
||||||
|
RoseGraph &g = build.g;
|
||||||
|
DEBUG_PRINTF("%zu castle leftfix merge candidates\n", cands.size());
|
||||||
|
|
||||||
|
for (auto it = cands.begin(); it != cands.end(); ++it) {
|
||||||
|
left_id &cand_1 = *it;
|
||||||
|
vector<RoseVertex> &verts_1 = eng_verts[cand_1];
|
||||||
|
if (verts_1.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto jt = next(it); jt != cands.end(); ++jt) {
|
||||||
|
const left_id &cand_2 = *jt;
|
||||||
|
vector<RoseVertex> &verts_2 = eng_verts[cand_2];
|
||||||
|
if (verts_2.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(cand_1.castle()->reach() == cand_2.castle()->reach());
|
||||||
|
|
||||||
|
if (!checkVerticesOkForLeftfixMerge(build, verts_1, verts_2)) {
|
||||||
|
DEBUG_PRINTF("not mergeable\n");
|
||||||
|
continue; // next cand_2
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_PRINTF("castle1=%p (size %zu)\n", cand_1.castle(),
|
||||||
|
cand_1.castle()->repeats.size());
|
||||||
|
DEBUG_PRINTF("castle2=%p (size %zu)\n", cand_2.castle(),
|
||||||
|
cand_2.castle()->repeats.size());
|
||||||
|
|
||||||
|
map<u32, u32> top_map;
|
||||||
|
if (!mergeCastle(*cand_1.castle(), *cand_2.castle(), top_map)) {
|
||||||
|
DEBUG_PRINTF("couldn't merge\n");
|
||||||
|
continue; // next cand_2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update castle2's roses to point to castle1 now.
|
||||||
|
shared_ptr<CastleProto> winner = g[verts_1.front()].left.castle;
|
||||||
|
for (auto v : verts_2) {
|
||||||
|
assert(g[v].left.castle.get() == cand_2.castle());
|
||||||
|
g[v].left.castle = winner;
|
||||||
|
for (const auto &e : in_edges_range(v, g)) {
|
||||||
|
g[e].rose_top = top_map.at(g[e].rose_top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
insert(&verts_1, verts_1.end(), verts_2);
|
||||||
|
verts_2.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges castles with the same reach together regardless of where in the rose
|
||||||
|
* graph they are. Note: there is no requirement for the castles to have common
|
||||||
|
* parent or target vertices.
|
||||||
|
*
|
||||||
|
* There are no heuristics for reducing block mode merges as castle speed
|
||||||
|
* mainly depends on the reach being scanned.
|
||||||
|
*/
|
||||||
|
void mergeCastleLeftfixes(RoseBuildImpl &build) {
|
||||||
DEBUG_PRINTF("entry\n");
|
DEBUG_PRINTF("entry\n");
|
||||||
|
|
||||||
if (!tbi.cc.grey.mergeRose || !tbi.cc.grey.roseMultiTopRoses ||
|
if (!build.cc.grey.mergeRose || !build.cc.grey.roseMultiTopRoses
|
||||||
!tbi.cc.grey.allowCastle) {
|
|| !build.cc.grey.allowCastle) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RoseGraph &g = tbi.g;
|
RoseGraph &g = build.g;
|
||||||
|
|
||||||
map<CharReach, RoseBouquet> by_reach;
|
insertion_ordered_map<left_id, vector<RoseVertex>> eng_verts;
|
||||||
|
|
||||||
for (auto v : vertices_range(g)) {
|
for (auto v : vertices_range(g)) {
|
||||||
if (!g[v].left) {
|
if (!g[v].left.castle) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle single-parent infixes only.
|
// Handle infixes only.
|
||||||
if (tbi.isRootSuccessor(v)) {
|
if (build.isRootSuccessor(v)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const left_id left(g[v].left);
|
eng_verts[g[v].left].push_back(v);
|
||||||
|
|
||||||
// Only non-transient for the moment.
|
|
||||||
if (contains(tbi.transient, left)) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!left.castle()) {
|
map<CharReach, vector<left_id>> by_reach;
|
||||||
continue;
|
for (const auto &left : eng_verts | map_keys) {
|
||||||
|
by_reach[left.castle()->reach()].push_back(left);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CastleProto &castle = *left.castle();
|
vector<vector<left_id>> chunks;
|
||||||
const CharReach &cr = castle.reach();
|
for (auto &raw_group : by_reach | map_values) {
|
||||||
by_reach[cr].insert(left, v);
|
chunk(move(raw_group), &chunks, MERGE_CASTLE_GROUP_SIZE_MAX);
|
||||||
}
|
}
|
||||||
|
by_reach.clear();
|
||||||
|
|
||||||
for (auto &m : by_reach) {
|
DEBUG_PRINTF("chunked castles into %zu groups\n", chunks.size());
|
||||||
DEBUG_PRINTF("%zu castles for reach: %s\n", m.second.size(),
|
|
||||||
describeClass(m.first).c_str());
|
|
||||||
RoseBouquet &candidates = m.second;
|
|
||||||
deque<RoseBouquet> cand_groups;
|
|
||||||
chunkBouquets(candidates, cand_groups, MERGE_CASTLE_GROUP_SIZE_MAX);
|
|
||||||
candidates.clear();
|
|
||||||
|
|
||||||
for (auto &group : cand_groups) {
|
for (auto &chunk : chunks) {
|
||||||
mergeCastleChunk(tbi, group);
|
mergeCastleChunk(build, chunk, eng_verts);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user