Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ TIMESTAMP := $(shell date +"%Y%m%d_%H%M%S")

VERBOSE ?= 0
DEBUG ?= 0
USE_JEMALLOC ?= 0
BENCH_FILTER ?=

ifeq ($(VERBOSE),1)
Q :=
else
Expand All @@ -25,8 +27,15 @@ NASMFLAGS := -f elf64
CXXFLAGS := -std=c++23 -Wall -Wextra $(OPTFLAG) $(DBGFLAG) -Iinclude
AVXFLAGS := -mavx2
DEPFLAGS := -MMD -MP

# Base LDFLAGS
LDFLAGS :=

# Optional jemalloc linking
ifeq ($(USE_JEMALLOC),1)
LDFLAGS += -ljemalloc
endif

TEST_LDFLAGS := $(LDFLAGS) -lgtest -lgtest_main -pthread
BENCH_LDFLAGS := $(LDFLAGS) -lbenchmark -pthread

Expand Down
128 changes: 42 additions & 86 deletions include/complete_andersen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,8 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
}
}

// Reuse capacities for maps
Bitset delta;
Bitset mapped_delta;
// Reuse capacities for maps to prevent allocation inside the tight loop
Bitset mapped_pts;
Bitset mapped_loads;
Bitset mapped_stores;
Bitset mapped_copy;
Expand All @@ -84,6 +83,7 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
while (!current_worklist_.empty() || !next_worklist_.empty()) {
if (current_worklist_.empty()) {
std::swap(current_worklist_, next_worklist_);
// LRF Scheduling
std::sort(current_worklist_.begin(), current_worklist_.end(),
[&](uint32_t a, uint32_t b) {
return last_fired_[a] > last_fired_[b];
Expand All @@ -100,28 +100,27 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
in_worklist_[n] = 0;
last_fired_[n] = current_time_++;

delta = nodes_[n].pts;
delta.subtract(nodes_[n].old_pts);
if (delta.empty()) [[unlikely]]
if (nodes_[n].pts.empty()) [[unlikely]]
continue;

nodes_[n].old_pts.union_with(delta);

if constexpr (ENABLE_HCD) {
apply_hcd_online(n, delta);
apply_hcd_online(n);
}

mapped_delta.subtract(mapped_delta); // Clear (O(1))
mapped_pts.subtract(mapped_pts); // Clear (O(1))
if (!nodes_[n].loads.empty() || !nodes_[n].stores.empty()) {
delta.for_each([&](size_t v) { mapped_delta.set(find(v)); });
nodes_[n].pts.for_each([&](size_t v) { mapped_pts.set(find(v)); });
}

// Evaluate Loads
if (!nodes_[n].loads.empty()) {
mapped_loads.subtract(mapped_loads);
nodes_[n].loads.for_each([&](size_t a) { mapped_loads.set(find(a)); });

mapped_delta.for_each([&](size_t rep_v) {
mapped_pts.for_each([&](size_t rep_v) {
new_edges = mapped_loads;
// Core Wave-front replacement: By removing copy edges that already
// exist, we ensure we only propagate facts for newly discovered pairs.
new_edges.subtract(nodes_[rep_v].copy);

if (!new_edges.empty()) {
Expand All @@ -135,13 +134,15 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
});
}

// Evaluate Stores
if (!nodes_[n].stores.empty()) {
mapped_stores.subtract(mapped_stores);
nodes_[n].stores.for_each(
[&](size_t b) { mapped_stores.set(find(b)); });

mapped_stores.for_each([&](size_t rep_b) {
new_edges = mapped_delta;
new_edges = mapped_pts;
// Core Wave-front replacement
new_edges.subtract(nodes_[rep_b].copy);

if (!new_edges.empty()) {
Expand All @@ -155,44 +156,28 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
});
}

// Evaluate Standard Copy Edges & LCD Check
mapped_copy.subtract(mapped_copy);
nodes_[n].copy.for_each([&](size_t z) { mapped_copy.set(find(z)); });
apply_lcd_online(n, delta, mapped_copy);
apply_lcd_online(n, mapped_copy);
}
}

[[nodiscard]] const Bitset &points_to(size_t var) {
uint32_t rep = static_cast<uint32_t>(var);
while (rep != rep_[rep]) {
rep = rep_[rep];
}
return nodes_[rep].pts;
return nodes_[find(static_cast<uint32_t>(var))].pts;
}

[[nodiscard]] bool may_alias(size_t a, size_t b) {
uint32_t rep_a = static_cast<uint32_t>(a);
while (rep_a != rep_[rep_a]) {
rep_a = rep_[rep_a];
}

uint32_t rep_b = static_cast<uint32_t>(b);
while (rep_b != rep_[rep_b]) {
rep_b = rep_[rep_b];
}

return nodes_[rep_a].pts.intersects(nodes_[rep_b].pts);
return nodes_[find(static_cast<uint32_t>(a))].pts.intersects(
nodes_[find(static_cast<uint32_t>(b))].pts);
}

[[nodiscard]] size_t num_vars() const { return num_vars_; }
[[nodiscard]] size_t num_constraints() const { return total_constraints_; }

void dump_points_to(const std::string &filename) const {
std::FILE *out = std::fopen(filename.c_str(), "wb");
if (!out) {
std::fprintf(stderr, "Error: Could not open file %s for writing.\n",
filename.c_str());
return;
}
if (!out) return;

std::vector<char> io_buffer(1024 * 1024);
std::setvbuf(out, io_buffer.data(), _IOFBF, io_buffer.size());
Expand All @@ -211,9 +196,7 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {

bool first = true;
nodes_[rep].pts.for_each([&](size_t target) {
if (!first)
std::fputs(", ", out);

if (!first) std::fputs(", ", out);
auto [p2, ec2] = std::to_chars(num_buf, num_buf + 32, target);
std::fwrite(num_buf, 1, p2 - num_buf, out);
first = false;
Expand All @@ -226,9 +209,8 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
}

private:
struct Node {
struct alignas(64) Node {
Bitset pts;
Bitset old_pts;
Bitset copy;
Bitset loads;
Bitset stores;
Expand Down Expand Up @@ -292,37 +274,25 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
uint32_t collapse_nodes(uint32_t u, uint32_t v) {
u = find(u);
v = find(v);
if (u == v)
return u;

// arbitrarily merge into smaller ID, ensures faster collapse.
if (u > v)
std::swap(u, v);
if (u == v) return u;

if (u > v) std::swap(u, v);
rep_[v] = u;

// Consolidate constraints to the new representative root
nodes_[u].pts.union_with(nodes_[v].pts);

// Hard free old_pts to release retained capacity & ensure full difference
// propagation
nodes_[u].old_pts = Bitset();

nodes_[u].copy.union_with(nodes_[v].copy);
nodes_[u].loads.union_with(nodes_[v].loads);
nodes_[u].stores.union_with(nodes_[v].stores);

// Discard collapsed node memory
// Hard free discarded node memory
nodes_[v].pts = Bitset();
nodes_[v].old_pts = Bitset();
nodes_[v].copy = Bitset();
nodes_[v].loads = Bitset();
nodes_[v].stores = Bitset();

push_worklist(u);
if (in_worklist_[v]) {
in_worklist_[v] = 0;
}
if (in_worklist_[v]) in_worklist_[v] = 0;
return u;
}

Expand Down Expand Up @@ -392,8 +362,7 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
}
}

if (pushed)
continue;
if (pushed) continue;

off_call_stack.pop_back();

Expand All @@ -409,25 +378,22 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
off_scc_stack.pop_back();
off_in_stack[v] = 0;
scc.push_back(v);
if (v == u)
break;
if (v == u) break;
}

if (scc.size() > 1) {
uint32_t non_ref = UINT32_MAX;
bool has_ref = false;
for (uint32_t v : scc) {
if (v < num_vars_) {
if (non_ref == UINT32_MAX || v < non_ref)
non_ref = v;
if (non_ref == UINT32_MAX || v < non_ref) non_ref = v;
} else {
has_ref = true;
}
}
if (has_ref && non_ref != UINT32_MAX) {
for (uint32_t v : scc) {
if (v >= num_vars_)
hcd_map_[v - num_vars_] = non_ref;
if (v >= num_vars_) hcd_map_[v - num_vars_] = non_ref;
}
}
}
Expand All @@ -436,37 +402,32 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
}
}

void apply_hcd_online(uint32_t &n, const Bitset &delta) {
void apply_hcd_online(uint32_t &n) {
uint32_t hcd_target = hcd_map_[n];
if (hcd_target != UINT32_MAX) {
hcd_target = find(hcd_target);
bool collapsed = false;

delta.for_each([&](size_t v) {
nodes_[n].pts.for_each([&](size_t v) {
uint32_t rep_v = find(v);
if (rep_v != hcd_target) {
hcd_target = collapse_nodes(rep_v, hcd_target);
collapsed = true;
}
});

if (collapsed) {
n = find(n);
}
if (collapsed) n = find(n);
}
}

void apply_lcd_online(uint32_t &n, const Bitset &delta,
const Bitset &mapped_copy) {
void apply_lcd_online(uint32_t &n, const Bitset &mapped_copy) {
mapped_copy.for_each([&](size_t rep_z) {
n = find(n);
uint32_t z = find(rep_z);
if (n == z)
return;
if (n == z) return;

if constexpr (ENABLE_LCD) {
if (nodes_[n].pts.count() == nodes_[z].pts.count() &&
nodes_[n].pts == nodes_[z].pts) {
if (nodes_[n].pts == nodes_[z].pts) {
uint64_t edge_key = (static_cast<uint64_t>(n) << 32) | z;
if (lcd_searched_.insert(edge_key).second) {
online_tarjan(z);
Expand All @@ -477,7 +438,7 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
}

if (n != z) {
if (nodes_[z].pts.union_with(delta)) {
if (nodes_[z].pts.union_with(nodes_[n].pts)) {
push_worklist(z);
}
}
Expand Down Expand Up @@ -510,10 +471,8 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
bool pushed = false;
while (frame.current_idx < frame.pool_end) {
uint32_t v = tjn_edgpool_[frame.current_idx++];
if (v == u)
continue;
if (v == u) continue;

// LCD identical points-to set heuristic
if (nodes_[v].pts == nodes_[find(current_root)].pts) {
if (dfn_[v] == 0) {
dfn_[v] = low_[v] = tarjan_timer_++;
Expand All @@ -536,8 +495,7 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
}
}

if (pushed)
continue;
if (pushed) continue;

// Free the pseudo stack allocator
tjn_edgpool_.resize(frame.pool_start);
Expand All @@ -558,11 +516,8 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
uint32_t v = scc_stack_.back();
scc_stack_.pop_back();
in_stack_[v] = 0;
if (v != root) {
root = collapse_nodes(v, root);
}
if (v == u)
break;
if (v != root) root = collapse_nodes(v, root);
if (v == u) break;
}
}
}
Expand All @@ -573,6 +528,7 @@ template <typename Bitset = SparseBitsetASM> class CompleteAndersen {
dfn_[u] = 0;
low_[u] = 0;
}

visited_nodes_.clear();
scc_stack_.clear();
tarjan_timer_ = 1;
Expand Down
2 changes: 1 addition & 1 deletion scripts/run_pin.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash
export PIN_ROOT="$(pwd)/.cache/pin-external-4.2-99776-g21d818fa2-gcc-linux"
TARGET_PROGRAM="$(pwd)/build/bin/pointerflow_runner"
INPUT_FILE="$(pwd)/tests/constraints/duktape_constraints.txt"
INPUT_FILE="$(pwd)/tests/constraints/lua_constraints.txt"
BRANCH_TOOL="bimodal_predictor"

TOOL_DIR="$PIN_ROOT/source/tools/ManualExamples"
Expand Down
Loading
Loading