mirror of
https://github.com/VectorCamp/vectorscan.git
synced 2025-06-28 16:41:01 +03:00
rose: role aliasing improvements
These changes improve the performance of the role aliasing passes on very large cases and fix a couple of small errors in the left and right merge passes as well.
This commit is contained in:
parent
a55bbe657c
commit
988ea6b4e1
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015-2016, Intel Corporation
|
* Copyright (c) 2015-2017, Intel Corporation
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
@ -47,6 +47,7 @@
|
|||||||
#include "util/container.h"
|
#include "util/container.h"
|
||||||
#include "util/graph.h"
|
#include "util/graph.h"
|
||||||
#include "util/graph_range.h"
|
#include "util/graph_range.h"
|
||||||
|
#include "util/hash.h"
|
||||||
#include "util/order_check.h"
|
#include "util/order_check.h"
|
||||||
#include "util/ue2_containers.h"
|
#include "util/ue2_containers.h"
|
||||||
|
|
||||||
@ -111,11 +112,14 @@ struct AliasInEdge : EdgeAndVertex {
|
|||||||
|
|
||||||
class CandidateSet {
|
class CandidateSet {
|
||||||
public:
|
public:
|
||||||
typedef set<RoseVertex>::iterator iterator;
|
using key_type = RoseVertex;
|
||||||
typedef RoseVertex key_type;
|
using iterator = set<RoseVertex>::iterator;
|
||||||
|
using const_iterator = set<RoseVertex>::const_iterator;
|
||||||
|
|
||||||
iterator begin() { return main_cont.begin(); }
|
iterator begin() { return main_cont.begin(); }
|
||||||
iterator end() { return main_cont.end(); }
|
iterator end() { return main_cont.end(); }
|
||||||
|
const_iterator begin() const { return main_cont.begin(); }
|
||||||
|
const_iterator end() const { return main_cont.end(); }
|
||||||
|
|
||||||
bool contains(RoseVertex a) const {
|
bool contains(RoseVertex a) const {
|
||||||
return hash_cont.find(a) != hash_cont.end();
|
return hash_cont.find(a) != hash_cont.end();
|
||||||
@ -451,37 +455,6 @@ bool sameRightRoleProperties(const RoseBuildImpl &build, RoseVertex a,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash on some deterministic props checked in sameRoleProperties + properties
|
|
||||||
* required for right equivalence.
|
|
||||||
*/
|
|
||||||
static
|
|
||||||
size_t hashRightRoleProperties(RoseVertex v, const RoseGraph &g) {
|
|
||||||
using boost::hash_combine;
|
|
||||||
using boost::hash_range;
|
|
||||||
|
|
||||||
const RoseVertexProps &props = g[v];
|
|
||||||
|
|
||||||
size_t val = 0;
|
|
||||||
hash_combine(val, hash_range(begin(props.reports), end(props.reports)));
|
|
||||||
|
|
||||||
if (props.suffix) {
|
|
||||||
const auto &suffix = props.suffix;
|
|
||||||
if (suffix.castle) {
|
|
||||||
hash_combine(val, suffix.castle->reach());
|
|
||||||
hash_combine(val, suffix.castle->repeats.size());
|
|
||||||
}
|
|
||||||
if (suffix.graph) {
|
|
||||||
hash_combine(val, num_vertices(*suffix.graph));
|
|
||||||
}
|
|
||||||
if (suffix.haig) {
|
|
||||||
hash_combine(val, hash_dfa(*suffix.haig));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
void mergeEdgeAdd(RoseVertex u, RoseVertex v, const RoseEdge &from_edge,
|
void mergeEdgeAdd(RoseVertex u, RoseVertex v, const RoseEdge &from_edge,
|
||||||
const RoseEdge *to_edge, RoseGraph &g) {
|
const RoseEdge *to_edge, RoseGraph &g) {
|
||||||
@ -684,16 +657,6 @@ void findCandidates(const RoseBuildImpl &build, CandidateSet *candidates) {
|
|||||||
num_vertices(build.g));
|
num_vertices(build.g));
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
RoseVertex pickSucc(const RoseVertex v, const RoseGraph &g) {
|
|
||||||
RoseGraph::adjacency_iterator ai, ae;
|
|
||||||
tie(ai, ae) = adjacent_vertices(v, g);
|
|
||||||
if (ai == ae) {
|
|
||||||
return RoseGraph::null_vertex();
|
|
||||||
}
|
|
||||||
return *ai;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
RoseVertex pickPred(const RoseVertex v, const RoseGraph &g,
|
RoseVertex pickPred(const RoseVertex v, const RoseGraph &g,
|
||||||
const RoseBuildImpl &build) {
|
const RoseBuildImpl &build) {
|
||||||
@ -854,7 +817,7 @@ void pruneUnusedTops(NGHolder &h, const RoseGraph &g,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(isCorrectlyTopped(h));
|
assert(isCorrectlyTopped(h));
|
||||||
DEBUG_PRINTF("prunning unused tops\n");
|
DEBUG_PRINTF("pruning unused tops\n");
|
||||||
ue2::flat_set<u32> used_tops;
|
ue2::flat_set<u32> used_tops;
|
||||||
for (auto v : verts) {
|
for (auto v : verts) {
|
||||||
assert(g[v].left.graph.get() == &h);
|
assert(g[v].left.graph.get() == &h);
|
||||||
@ -1427,62 +1390,95 @@ bool attemptRoseMerge(RoseBuildImpl &build, bool preds_same, RoseVertex a,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Buckets that only contain one vertex are never going to lead to a
|
||||||
|
* merge.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void removeSingletonBuckets(vector<vector<RoseVertex>> &buckets) {
|
||||||
|
auto it = remove_if(
|
||||||
|
begin(buckets), end(buckets),
|
||||||
|
[](const vector<RoseVertex> &bucket) { return bucket.size() < 2; });
|
||||||
|
if (it != end(buckets)) {
|
||||||
|
DEBUG_PRINTF("deleting %zu singleton buckets\n",
|
||||||
|
distance(it, end(buckets)));
|
||||||
|
buckets.erase(it, end(buckets));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void buildInvBucketMap(const vector<vector<RoseVertex>> &buckets,
|
||||||
|
ue2::unordered_map<RoseVertex, size_t> &inv) {
|
||||||
|
inv.clear();
|
||||||
|
for (size_t i = 0; i < buckets.size(); i++) {
|
||||||
|
for (auto v : buckets[i]) {
|
||||||
|
assert(!contains(inv, v));
|
||||||
|
inv.emplace(v, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Generic splitter that will use the given split function to partition
|
||||||
|
* the vector of buckets, then remove buckets with <= 1 entry.
|
||||||
|
*/
|
||||||
|
template <class SplitFunction>
|
||||||
|
void splitAndFilterBuckets(vector<vector<RoseVertex>> &buckets,
|
||||||
|
const SplitFunction &make_split_key) {
|
||||||
|
if (buckets.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<vector<RoseVertex>> out;
|
||||||
|
|
||||||
|
// Mapping from split key value to new bucket index.
|
||||||
|
using key_type = decltype(make_split_key(RoseGraph::null_vertex()));
|
||||||
|
unordered_map<key_type, size_t> dest_map;
|
||||||
|
dest_map.reserve(buckets.front().size());
|
||||||
|
|
||||||
|
for (const auto &bucket : buckets) {
|
||||||
|
assert(!bucket.empty());
|
||||||
|
dest_map.clear();
|
||||||
|
for (RoseVertex v : bucket) {
|
||||||
|
auto p = dest_map.emplace(make_split_key(v), out.size());
|
||||||
|
if (p.second) { // New key, add a bucket.
|
||||||
|
out.emplace_back();
|
||||||
|
}
|
||||||
|
auto out_bucket = p.first->second;
|
||||||
|
out[out_bucket].push_back(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out.size() == buckets.size()) {
|
||||||
|
return; // No new buckets created.
|
||||||
|
}
|
||||||
|
|
||||||
|
buckets = move(out);
|
||||||
|
removeSingletonBuckets(buckets);
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void splitByReportSuffixBehaviour(const RoseGraph &g,
|
void splitByReportSuffixBehaviour(const RoseGraph &g,
|
||||||
vector<vector<RoseVertex>> &buckets,
|
vector<vector<RoseVertex>> &buckets) {
|
||||||
ue2::unordered_map<RoseVertex, size_t> &inv) {
|
// Split by report set and suffix info.
|
||||||
/* vertices with different report/suffixes can never be considered for right
|
auto make_split_key = [&g](RoseVertex v) {
|
||||||
* merge. */
|
return hash_all(g[v].reports, g[v].suffix);
|
||||||
vector<vector<RoseVertex>> out;
|
};
|
||||||
for (const vector<RoseVertex> &b : buckets) {
|
splitAndFilterBuckets(buckets, make_split_key);
|
||||||
assert(!b.empty());
|
|
||||||
map<pair<flat_set<ReportID>, RoseSuffixInfo>, size_t> dest_map;
|
|
||||||
for (RoseVertex v : b) {
|
|
||||||
auto key = decltype(dest_map)::key_type(g[v].reports, g[v].suffix);
|
|
||||||
size_t out_bucket;
|
|
||||||
if (contains(dest_map, key)) {
|
|
||||||
out_bucket = dest_map[key];
|
|
||||||
} else {
|
|
||||||
out_bucket = out.size();
|
|
||||||
out.push_back(vector<RoseVertex>());
|
|
||||||
dest_map[key] = out_bucket;
|
|
||||||
}
|
|
||||||
out[out_bucket].push_back(v);
|
|
||||||
inv[v] = out_bucket;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
buckets.swap(out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void splitByLiteralTable(const RoseBuildImpl &build,
|
void splitByLiteralTable(const RoseBuildImpl &build,
|
||||||
vector<vector<RoseVertex>> &buckets,
|
vector<vector<RoseVertex>> &buckets) {
|
||||||
ue2::unordered_map<RoseVertex, size_t> &inv) {
|
|
||||||
const RoseGraph &g = build.g;
|
const RoseGraph &g = build.g;
|
||||||
|
|
||||||
vector<vector<RoseVertex>> out;
|
// Split by literal table.
|
||||||
|
auto make_split_key = [&](RoseVertex v) {
|
||||||
for (const auto &bucket : buckets) {
|
const auto &lits = g[v].literals;
|
||||||
assert(!bucket.empty());
|
assert(!lits.empty());
|
||||||
map<rose_literal_table, size_t> dest_map;
|
return build.literals.right.at(*lits.begin()).table;
|
||||||
for (RoseVertex v : bucket) {
|
};
|
||||||
auto table = build.literals.right.at(*g[v].literals.begin()).table;
|
splitAndFilterBuckets(buckets, make_split_key);
|
||||||
size_t out_bucket;
|
|
||||||
if (contains(dest_map, table)) {
|
|
||||||
out_bucket = dest_map[table];
|
|
||||||
} else {
|
|
||||||
out_bucket = out.size();
|
|
||||||
out.push_back(vector<RoseVertex>());
|
|
||||||
dest_map[table] = out_bucket;
|
|
||||||
}
|
|
||||||
out[out_bucket].push_back(v);
|
|
||||||
inv[v] = out_bucket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buckets.swap(out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@ -1543,6 +1539,9 @@ void splitByNeighbour(const RoseGraph &g, vector<vector<RoseVertex>> &buckets,
|
|||||||
}
|
}
|
||||||
insert(&buckets, buckets.end(), extras);
|
insert(&buckets, buckets.end(), extras);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeSingletonBuckets(buckets);
|
||||||
|
buildInvBucketMap(buckets, inv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@ -1551,16 +1550,35 @@ splitDiamondMergeBuckets(CandidateSet &candidates, const RoseBuildImpl &build) {
|
|||||||
const RoseGraph &g = build.g;
|
const RoseGraph &g = build.g;
|
||||||
|
|
||||||
vector<vector<RoseVertex>> buckets(1);
|
vector<vector<RoseVertex>> buckets(1);
|
||||||
ue2::unordered_map<RoseVertex, size_t> inv;
|
buckets[0].reserve(candidates.size());
|
||||||
for (RoseVertex v : candidates) {
|
insert(&buckets[0], buckets[0].end(), candidates);
|
||||||
buckets[0].push_back(v);
|
|
||||||
inv[v] = 0;
|
DEBUG_PRINTF("at start, %zu candidates in 1 bucket\n", candidates.size());
|
||||||
|
|
||||||
|
splitByReportSuffixBehaviour(g, buckets);
|
||||||
|
DEBUG_PRINTF("split by report/suffix, %zu buckets\n", buckets.size());
|
||||||
|
if (buckets.empty()) {
|
||||||
|
return buckets;
|
||||||
}
|
}
|
||||||
|
|
||||||
splitByReportSuffixBehaviour(g, buckets, inv);
|
splitByLiteralTable(build, buckets);
|
||||||
splitByLiteralTable(build, buckets, inv);
|
DEBUG_PRINTF("split by lit table, %zu buckets\n", buckets.size());
|
||||||
|
if (buckets.empty()) {
|
||||||
|
return buckets;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neighbour splits require inverse map.
|
||||||
|
ue2::unordered_map<RoseVertex, size_t> inv;
|
||||||
|
buildInvBucketMap(buckets, inv);
|
||||||
|
|
||||||
splitByNeighbour(g, buckets, inv, true);
|
splitByNeighbour(g, buckets, inv, true);
|
||||||
|
DEBUG_PRINTF("split by successor, %zu buckets\n", buckets.size());
|
||||||
|
if (buckets.empty()) {
|
||||||
|
return buckets;
|
||||||
|
}
|
||||||
|
|
||||||
splitByNeighbour(g, buckets, inv, false);
|
splitByNeighbour(g, buckets, inv, false);
|
||||||
|
DEBUG_PRINTF("split by predecessor, %zu buckets\n", buckets.size());
|
||||||
|
|
||||||
return buckets;
|
return buckets;
|
||||||
}
|
}
|
||||||
@ -1677,55 +1695,62 @@ vector<RoseVertex>::iterator findLeftMergeSibling(
|
|||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
static never_inline
|
static
|
||||||
void leftMergePass(CandidateSet &candidates, RoseBuildImpl &build,
|
void getLeftMergeSiblings(const RoseBuildImpl &build, RoseVertex a,
|
||||||
vector<RoseVertex> *dead, RoseAliasingInfo &rai) {
|
vector<RoseVertex> &siblings) {
|
||||||
DEBUG_PRINTF("begin (%zu)\n", candidates.size());
|
|
||||||
RoseGraph &g = build.g;
|
|
||||||
vector<RoseVertex> siblings;
|
|
||||||
|
|
||||||
CandidateSet::iterator it = candidates.begin();
|
|
||||||
while (it != candidates.end()) {
|
|
||||||
RoseVertex a = *it;
|
|
||||||
CandidateSet::iterator ait = it;
|
|
||||||
++it;
|
|
||||||
|
|
||||||
// We have to find a sibling to merge `a' with, and we select between
|
// We have to find a sibling to merge `a' with, and we select between
|
||||||
// two approaches to minimize the number of vertices we have to
|
// two approaches to minimize the number of vertices we have to
|
||||||
// examine; which we use depends on the shape of the graph.
|
// examine; which we use depends on the shape of the graph.
|
||||||
|
|
||||||
|
const RoseGraph &g = build.g;
|
||||||
assert(!g[a].literals.empty());
|
assert(!g[a].literals.empty());
|
||||||
u32 lit_id = *g[a].literals.begin();
|
u32 lit_id = *g[a].literals.begin();
|
||||||
const auto &verts = build.literal_info.at(lit_id).vertices;
|
const auto &verts = build.literal_info.at(lit_id).vertices;
|
||||||
RoseVertex pred = pickPred(a, g, build);
|
RoseVertex pred = pickPred(a, g, build);
|
||||||
|
|
||||||
siblings.clear();
|
siblings.clear();
|
||||||
if (pred == RoseGraph::null_vertex() || build.isAnyStart(pred)
|
|
||||||
|| out_degree(pred, g) > verts.size()) {
|
if (pred == RoseGraph::null_vertex() || build.isAnyStart(pred) ||
|
||||||
|
out_degree(pred, g) > verts.size()) {
|
||||||
// Select sibling from amongst the vertices that share a literal.
|
// Select sibling from amongst the vertices that share a literal.
|
||||||
siblings.insert(siblings.end(), verts.begin(), verts.end());
|
insert(&siblings, siblings.end(), verts);
|
||||||
} else {
|
} else {
|
||||||
// Select sibling from amongst the vertices that share a
|
// Select sibling from amongst the vertices that share a
|
||||||
// predecessor.
|
// predecessor.
|
||||||
insert(&siblings, siblings.end(), adjacent_vertices(pred, g));
|
insert(&siblings, siblings.end(), adjacent_vertices(pred, g));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto jt = findLeftMergeSibling(siblings.begin(), siblings.end(), a,
|
static never_inline
|
||||||
build, rai, candidates);
|
void leftMergePass(CandidateSet &candidates, RoseBuildImpl &build,
|
||||||
|
vector<RoseVertex> *dead, RoseAliasingInfo &rai) {
|
||||||
|
DEBUG_PRINTF("begin (%zu)\n", candidates.size());
|
||||||
|
vector<RoseVertex> siblings;
|
||||||
|
|
||||||
|
auto it = candidates.begin();
|
||||||
|
while (it != candidates.end()) {
|
||||||
|
RoseVertex a = *it;
|
||||||
|
CandidateSet::iterator ait = it;
|
||||||
|
++it;
|
||||||
|
|
||||||
|
getLeftMergeSiblings(build, a, siblings);
|
||||||
|
|
||||||
|
auto jt = siblings.begin();
|
||||||
|
while (jt != siblings.end()) {
|
||||||
|
jt = findLeftMergeSibling(jt, siblings.end(), a, build, rai,
|
||||||
|
candidates);
|
||||||
if (jt == siblings.end()) {
|
if (jt == siblings.end()) {
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
RoseVertex b = *jt;
|
RoseVertex b = *jt;
|
||||||
|
if (attemptRoseMerge(build, true, a, b, false, rai)) {
|
||||||
if (!attemptRoseMerge(build, true, a, b, 0, rai)) {
|
|
||||||
DEBUG_PRINTF("rose fail\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
mergeVerticesLeft(a, b, build, rai);
|
mergeVerticesLeft(a, b, build, rai);
|
||||||
dead->push_back(a);
|
dead->push_back(a);
|
||||||
candidates.erase(ait);
|
candidates.erase(ait);
|
||||||
|
break; // consider next a
|
||||||
|
}
|
||||||
|
++jt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PRINTF("%zu candidates remaining\n", candidates.size());
|
DEBUG_PRINTF("%zu candidates remaining\n", candidates.size());
|
||||||
@ -1810,91 +1835,49 @@ vector<RoseVertex>::const_iterator findRightMergeSibling(
|
|||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Iter>
|
|
||||||
static
|
static
|
||||||
void split(map<RoseVertex, size_t> &keys, size_t *next_key, Iter it,
|
void splitByRightProps(const RoseGraph &g,
|
||||||
const Iter end) {
|
vector<vector<RoseVertex>> &buckets) {
|
||||||
map<size_t, size_t> new_keys;
|
// Successor vector used in make_split_key. We declare it here so we can
|
||||||
|
// reuse storage.
|
||||||
|
vector<RoseVertex> succ;
|
||||||
|
|
||||||
for (; it != end; ++it) {
|
// Split by {successors, literals, reports}.
|
||||||
RoseVertex v = *it;
|
auto make_split_key = [&](RoseVertex v) {
|
||||||
size_t ok = keys[v];
|
succ.clear();
|
||||||
size_t nk;
|
insert(&succ, succ.end(), adjacent_vertices(v, g));
|
||||||
if (contains(new_keys, ok)) {
|
sort(succ.begin(), succ.end());
|
||||||
nk = new_keys[ok];
|
return hash_all(g[v].literals, g[v].reports, succ);
|
||||||
} else {
|
};
|
||||||
nk = (*next_key)++;
|
splitAndFilterBuckets(buckets, make_split_key);
|
||||||
new_keys[ok] = nk;
|
|
||||||
}
|
|
||||||
keys[v] = nk;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static never_inline
|
static never_inline
|
||||||
void buildCandidateRightSiblings(CandidateSet &candidates, RoseBuildImpl &build,
|
vector<vector<RoseVertex>>
|
||||||
map<size_t, vector<RoseVertex>> &sibling_cache,
|
splitRightMergeBuckets(const CandidateSet &candidates,
|
||||||
map<RoseVertex, size_t> &keys_ext) {
|
const RoseBuildImpl &build) {
|
||||||
RoseGraph &g = build.g;
|
const RoseGraph &g = build.g;
|
||||||
|
|
||||||
size_t next_key = 1;
|
vector<vector<RoseVertex>> buckets(1);
|
||||||
map<RoseVertex, size_t> keys;
|
buckets[0].reserve(candidates.size());
|
||||||
|
insert(&buckets[0], buckets[0].end(), candidates);
|
||||||
|
|
||||||
for (const auto &c : candidates) {
|
DEBUG_PRINTF("at start, %zu candidates in 1 bucket\n", candidates.size());
|
||||||
keys[c] = 0;
|
|
||||||
|
splitByReportSuffixBehaviour(g, buckets);
|
||||||
|
DEBUG_PRINTF("split by report/suffix, %zu buckets\n", buckets.size());
|
||||||
|
if (buckets.empty()) {
|
||||||
|
return buckets;
|
||||||
}
|
}
|
||||||
|
|
||||||
set<RoseVertex> done_succ;
|
splitByRightProps(g, buckets);
|
||||||
set<u32> done_lit;
|
DEBUG_PRINTF("split by right-merge properties, %zu buckets\n",
|
||||||
|
buckets.size());
|
||||||
for (auto a : candidates) {
|
if (buckets.empty()) {
|
||||||
assert(!g[a].literals.empty());
|
return buckets;
|
||||||
u32 lit_id = *g[a].literals.begin();
|
|
||||||
RoseVertex succ = pickSucc(a, g);
|
|
||||||
const auto &verts = build.literal_info.at(lit_id).vertices;
|
|
||||||
if (succ != RoseGraph::null_vertex()
|
|
||||||
&& in_degree(succ, g) < verts.size()) {
|
|
||||||
if (!done_succ.insert(succ).second) {
|
|
||||||
continue; // succ already in done_succ.
|
|
||||||
}
|
|
||||||
RoseGraph::inv_adjacency_iterator ai, ae;
|
|
||||||
tie (ai, ae) = inv_adjacent_vertices(succ, g);
|
|
||||||
split(keys, &next_key, ai, ae);
|
|
||||||
} else {
|
|
||||||
if (!done_lit.insert(lit_id).second) {
|
|
||||||
continue; // lit_id already in done_lit.
|
|
||||||
}
|
|
||||||
split(keys, &next_key, verts.begin(), verts.end());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
map<size_t, map<size_t, size_t>> int_to_ext;
|
return buckets;
|
||||||
|
|
||||||
for (const auto &key : keys) {
|
|
||||||
RoseVertex v = key.first;
|
|
||||||
u32 ext;
|
|
||||||
size_t rph = hashRightRoleProperties(v, g);
|
|
||||||
if (contains(int_to_ext[key.second], rph)) {
|
|
||||||
ext = int_to_ext[key.second][rph];
|
|
||||||
} else {
|
|
||||||
ext = keys_ext.size();
|
|
||||||
int_to_ext[key.second][rph] = ext;
|
|
||||||
}
|
|
||||||
|
|
||||||
keys_ext[v] = ext;
|
|
||||||
sibling_cache[ext].push_back(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &siblings : sibling_cache | map_values) {
|
|
||||||
sort(siblings.begin(), siblings.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
const vector<RoseVertex> &getCandidateRightSiblings(
|
|
||||||
const map<size_t, vector<RoseVertex>> &sibling_cache,
|
|
||||||
map<RoseVertex, size_t> &keys, RoseVertex a) {
|
|
||||||
size_t key = keys.at(a);
|
|
||||||
return sibling_cache.at(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static never_inline
|
static never_inline
|
||||||
@ -1903,45 +1886,31 @@ void rightMergePass(CandidateSet &candidates, RoseBuildImpl &build,
|
|||||||
RoseAliasingInfo &rai) {
|
RoseAliasingInfo &rai) {
|
||||||
DEBUG_PRINTF("begin\n");
|
DEBUG_PRINTF("begin\n");
|
||||||
|
|
||||||
map<size_t, vector<RoseVertex>> sibling_cache;
|
if (candidates.empty()) {
|
||||||
map<RoseVertex, size_t> keys;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
buildCandidateRightSiblings(candidates, build, sibling_cache, keys);
|
auto buckets = splitRightMergeBuckets(candidates, build);
|
||||||
|
|
||||||
CandidateSet::iterator it = candidates.begin();
|
for (const auto &bucket : buckets) {
|
||||||
while (it != candidates.end()) {
|
assert(!bucket.empty());
|
||||||
|
for (auto it = bucket.begin(); it != bucket.end(); it++) {
|
||||||
RoseVertex a = *it;
|
RoseVertex a = *it;
|
||||||
CandidateSet::iterator ait = it;
|
for (auto jt = bucket.begin(); jt != bucket.end(); jt++) {
|
||||||
++it;
|
jt = findRightMergeSibling(jt, bucket.end(), a, build, rai,
|
||||||
|
|
||||||
// We have to find a sibling to merge `a' with, and we select between
|
|
||||||
// two approaches to minimize the number of vertices we have to
|
|
||||||
// examine; which we use depends on the shape of the graph.
|
|
||||||
|
|
||||||
const vector<RoseVertex> &siblings
|
|
||||||
= getCandidateRightSiblings(sibling_cache, keys, a);
|
|
||||||
|
|
||||||
auto jt = siblings.begin();
|
|
||||||
while (jt != siblings.end()) {
|
|
||||||
jt = findRightMergeSibling(jt, siblings.end(), a, build, rai,
|
|
||||||
candidates);
|
candidates);
|
||||||
if (jt == siblings.end()) {
|
if (jt == bucket.end()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (attemptRoseMerge(build, false, a, *jt, !mergeRoses, rai)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++jt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jt == siblings.end()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
RoseVertex b = *jt;
|
RoseVertex b = *jt;
|
||||||
|
if (attemptRoseMerge(build, false, a, b, !mergeRoses, rai)) {
|
||||||
mergeVerticesRight(a, b, build, rai);
|
mergeVerticesRight(a, b, build, rai);
|
||||||
dead->push_back(a);
|
dead->push_back(a);
|
||||||
candidates.erase(ait);
|
candidates.erase(a);
|
||||||
|
break; // consider next a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PRINTF("%zu candidates remaining\n", candidates.size());
|
DEBUG_PRINTF("%zu candidates remaining\n", candidates.size());
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015-2016, Intel Corporation
|
* Copyright (c) 2015-2017, Intel Corporation
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
@ -36,6 +36,7 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <boost/functional/hash.hpp>
|
||||||
#include <boost/iterator/iterator_facade.hpp>
|
#include <boost/iterator/iterator_facade.hpp>
|
||||||
#include <boost/unordered/unordered_map.hpp>
|
#include <boost/unordered/unordered_map.hpp>
|
||||||
#include <boost/unordered/unordered_set.hpp>
|
#include <boost/unordered/unordered_set.hpp>
|
||||||
@ -318,6 +319,12 @@ public:
|
|||||||
friend void swap(flat_set &a, flat_set &b) {
|
friend void swap(flat_set &a, flat_set &b) {
|
||||||
a.swap(b);
|
a.swap(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Free hash function.
|
||||||
|
friend size_t hash_value(const flat_set &a) {
|
||||||
|
using boost::hash_value;
|
||||||
|
return hash_value(a.data);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -604,6 +611,12 @@ public:
|
|||||||
friend void swap(flat_map &a, flat_map &b) {
|
friend void swap(flat_map &a, flat_map &b) {
|
||||||
a.swap(b);
|
a.swap(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Free hash function.
|
||||||
|
friend size_t hash_value(const flat_map &a) {
|
||||||
|
using boost::hash_value;
|
||||||
|
return hash_value(a.data);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
Loading…
x
Reference in New Issue
Block a user