Skip to content
Snippets Groups Projects
Commit 5cbc382b authored by prrathi's avatar prrathi
Browse files

Merge branch 'main' of https://gitlab.engr.illinois.edu/llvm/hercules into gpu-cg

parents 59becc07 6e69a8f5
No related branches found
No related tags found
1 merge request!115GPU backend
Pipeline #201074 passed
This commit is part of merge request !115. Comments created here will be created in the context of that merge request.
...@@ -861,6 +861,7 @@ dependencies = [ ...@@ -861,6 +861,7 @@ dependencies = [
"serde", "serde",
"take_mut", "take_mut",
"tempfile", "tempfile",
"union-find",
] ]
[[package]] [[package]]
...@@ -2098,6 +2099,12 @@ version = "0.1.14" ...@@ -2098,6 +2099,12 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "union-find"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "039142448432983c34b64739f8526f8f233a1eec7a66e61b6ab29acfa781194e"
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
version = "0.2.2" version = "0.2.2"
......
...@@ -14,6 +14,7 @@ tempfile = "*" ...@@ -14,6 +14,7 @@ tempfile = "*"
either = "*" either = "*"
itertools = "*" itertools = "*"
take_mut = "*" take_mut = "*"
union-find = "*"
postcard = { version = "*", features = ["alloc"] } postcard = { version = "*", features = ["alloc"] }
serde = { version = "*", features = ["derive"] } serde = { version = "*", features = ["derive"] }
hercules_cg = { path = "../hercules_cg" } hercules_cg = { path = "../hercules_cg" }
......
...@@ -3,6 +3,7 @@ use std::iter::{empty, once, zip, FromIterator}; ...@@ -3,6 +3,7 @@ use std::iter::{empty, once, zip, FromIterator};
use bitvec::prelude::*; use bitvec::prelude::*;
use either::Either; use either::Either;
use union_find::{QuickFindUf, UnionBySize, UnionFind};
use hercules_cg::*; use hercules_cg::*;
use hercules_ir::*; use hercules_ir::*;
...@@ -551,6 +552,35 @@ fn mutating_objects<'a>( ...@@ -551,6 +552,35 @@ fn mutating_objects<'a>(
} }
} }
fn mutating_writes<'a>(
function: &'a Function,
mutator: NodeID,
objects: &'a CollectionObjects,
) -> Box<dyn Iterator<Item = NodeID> + 'a> {
match function.nodes[mutator.idx()] {
Node::Write {
collect,
data: _,
indices: _,
} => Box::new(once(collect)),
Node::Call {
control: _,
function: callee,
dynamic_constants: _,
ref args,
} => Box::new(args.into_iter().enumerate().filter_map(move |(idx, arg)| {
let callee_objects = &objects[&callee];
let param_obj = callee_objects.param_to_object(idx)?;
if callee_objects.is_mutated(param_obj) {
Some(*arg)
} else {
None
}
})),
_ => Box::new(empty()),
}
}
type Liveness = BTreeMap<NodeID, Vec<BTreeSet<NodeID>>>; type Liveness = BTreeMap<NodeID, Vec<BTreeSet<NodeID>>>;
/* /*
...@@ -579,27 +609,60 @@ fn spill_clones( ...@@ -579,27 +609,60 @@ fn spill_clones(
// Step 2: compute an interference graph from the liveness result. This // Step 2: compute an interference graph from the liveness result. This
// graph contains a vertex per node ID producing a collection value and an // graph contains a vertex per node ID producing a collection value and an
// edge per pair of node IDs that interfere. Nodes A and B interfere if node // edge per pair of node IDs that interfere. Nodes A and B interfere if node
// A is defined right above a point where node B is live. // A is defined right above a point where node B is live and A != B. Extra
// edges are drawn for forwarding reads - when there is a node A that is a
// forwarding read of a node B, A and B really have the same live range for
// the purpose of determining when spills are necessary, since forwarding
// reads can be thought of as nothing but pointer math. For this purpose, we
// maintain a union-find of nodes that form a forwarding read DAG (notably,
// phis and reduces are not considered forwarding reads). The more precise
// version of the interference condition is nodes A and B interfere is node
// A is defined right above a point where a node C is live where C is in the
// same union-find class as B.
// Assemble the union-find to group forwarding read DAGs.
let mut union_find = QuickFindUf::<UnionBySize>::new(editor.func().nodes.len());
for id in editor.node_ids() {
for forwarding_read in forwarding_reads(editor.func(), editor.func_id(), id, objects) {
union_find.union(id.idx(), forwarding_read.idx());
}
}
// Figure out which classes contain which node IDs, since we need to iterate
// the disjoint sets.
let mut disjoint_sets: BTreeMap<usize, Vec<NodeID>> = BTreeMap::new();
for id in editor.node_ids() {
disjoint_sets
.entry(union_find.find(id.idx()))
.or_default()
.push(id);
}
// Create the graph.
let mut edges = vec![]; let mut edges = vec![];
for (bb, liveness) in liveness { for (bb, liveness) in liveness {
let insts = &bbs.1[bb.idx()]; let insts = &bbs.1[bb.idx()];
for (node, live) in zip(insts, liveness.into_iter().skip(1)) { for (node, live) in zip(insts, liveness.into_iter().skip(1)) {
for live_node in live { for live_node in live {
if *node != live_node { for live_node in disjoint_sets[&union_find.find(live_node.idx())].iter() {
edges.push((*node, live_node)); if *node != *live_node {
edges.push((*node, *live_node));
}
} }
} }
} }
} }
// Step 3: filter edges (A, B) to just see edges where A uses B and A isn't // Step 3: filter edges (A, B) to just see edges where A uses B and A
// a terminating read. These are the edges that may require a spill. // mutates B. These are the edges that may require a spill.
let mut spill_edges = edges.into_iter().filter(|(a, b)| { let mut spill_edges = edges.into_iter().filter(|(a, b)| {
get_uses(&editor.func().nodes[a.idx()]) mutating_writes(editor.func(), *a, objects).any(|id| id == *b)
.as_ref() || (get_uses(&editor.func().nodes[a.idx()])
.into_iter() .as_ref()
.any(|u| *u == *b) .into_iter()
&& !terminating_reads(editor.func(), editor.func_id(), *a, objects).any(|id| id == *b) .any(|u| *u == *b)
&& (editor.func().nodes[a.idx()].is_phi()
|| editor.func().nodes[a.idx()].is_reduce()))
}); });
// Step 4: if there is a spill edge, spill it and return true. Otherwise, // Step 4: if there is a spill edge, spill it and return true. Otherwise,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment