Skip to content
Snippets Groups Projects
Commit 996018c6 authored by Russel Arbore's avatar Russel Arbore
Browse files

Get the products that are / aren't used in a sink

parent eebd3cef
No related branches found
No related tags found
1 merge request!25Misc. improvements
...@@ -659,6 +659,14 @@ impl Type { ...@@ -659,6 +659,14 @@ impl Type {
self.is_bool() || self.is_fixed() || self.is_float() self.is_bool() || self.is_fixed() || self.is_float()
} }
pub fn is_product(&self) -> bool {
if let Type::Product(_) = self {
true
} else {
false
}
}
pub fn is_array(&self) -> bool { pub fn is_array(&self) -> bool {
if let Type::Array(_, _) = self { if let Type::Array(_, _) = self {
true true
......
...@@ -366,8 +366,20 @@ impl PassManager { ...@@ -366,8 +366,20 @@ impl PassManager {
} }
} }
Pass::SROA => { Pass::SROA => {
self.make_def_uses();
self.make_reverse_postorders();
self.make_typing();
let def_uses = self.def_uses.as_ref().unwrap();
let reverse_postorders = self.reverse_postorders.as_ref().unwrap();
let typing = self.typing.as_ref().unwrap();
for idx in 0..self.module.functions.len() { for idx in 0..self.module.functions.len() {
sroa(&mut self.module.functions[idx]) sroa(
&mut self.module.functions[idx],
&def_uses[idx],
&reverse_postorders[idx],
&typing[idx],
&self.module.types,
);
} }
} }
Pass::Verify => { Pass::Verify => {
......
extern crate hercules_ir; extern crate hercules_ir;
use self::hercules_ir::dataflow::*;
use self::hercules_ir::def_use::*;
use self::hercules_ir::ir::*; use self::hercules_ir::ir::*;
/* /*
...@@ -37,6 +39,124 @@ use self::hercules_ir::ir::*; ...@@ -37,6 +39,124 @@ use self::hercules_ir::ir::*;
* but are retained when the product value is unbroken * but are retained when the product value is unbroken
* *
* The nodes above with the list marker "+" are retained for maintaining API/ABI * The nodes above with the list marker "+" are retained for maintaining API/ABI
* compatability with other Hercules functions and the host code. * compatability with other Hercules functions and the host code. These are
* called "sink" or "source" nodes in comments below.
*/ */
pub fn sroa(function: &mut Function) {} pub fn sroa(
function: &mut Function,
def_use: &ImmutableDefUseMap,
reverse_postorder: &Vec<NodeID>,
typing: &Vec<TypeID>,
types: &Vec<Type>,
) {
// Step 1: determine which sources of product values we want to try breaking
// up. We can determine easily on the soure side if a node produces a
// product that shouldn't be broken up by just examining the node type.
// However, the way that products are used is also important for determining
// if the product can be broken up. We backward dataflow this info to the
// sources of product values.
#[derive(PartialEq, Eq, Clone, Debug)]
enum ProductUseLattice {
// The product value used by this node is eventually used by a sink.
UsedBySink,
// This node uses multiple product values - the stored node ID indicates
// which is eventually used by a sink. This lattice value is produced by
// read and write nodes implementing partial indexing. We handle this
// specially since we want to optimize away partial indexing completely.
SpecificUsedBySink(NodeID),
// This node doesn't use a product node, or the product node it does use
// is not in turn used by a sink.
UnusedBySink,
}
impl Semilattice for ProductUseLattice {
fn meet(a: &Self, b: &Self) -> Self {
match (a, b) {
(Self::UsedBySink, _) | (_, Self::UsedBySink) => Self::UsedBySink,
(Self::SpecificUsedBySink(id1), Self::SpecificUsedBySink(id2)) => {
if id1 == id2 {
Self::SpecificUsedBySink(*id1)
} else {
Self::UsedBySink
}
}
(Self::SpecificUsedBySink(id), _) | (_, Self::SpecificUsedBySink(id)) => {
Self::SpecificUsedBySink(*id)
}
_ => Self::UnusedBySink,
}
}
fn bottom() -> Self {
Self::UsedBySink
}
fn top() -> Self {
Self::UnusedBySink
}
}
let product_uses = backward_dataflow(function, def_use, reverse_postorder, |succ_outs, id| {
match function.nodes[id.idx()] {
Node::Return {
control: _,
data: _,
} => {
if types[typing[id.idx()].idx()].is_product() {
ProductUseLattice::UsedBySink
} else {
ProductUseLattice::UnusedBySink
}
}
Node::Call {
function: _,
dynamic_constants: _,
args: _,
} => todo!(),
// For reads and writes, we only want to propagate the use of the
// product to the collect input of the node.
Node::Read {
collect,
indices: _,
}
| Node::Write {
collect,
data: _,
indices: _,
} => {
let meet = succ_outs
.iter()
.fold(ProductUseLattice::top(), |acc, latt| {
ProductUseLattice::meet(&acc, latt)
});
if meet == ProductUseLattice::UnusedBySink {
ProductUseLattice::UnusedBySink
} else {
ProductUseLattice::SpecificUsedBySink(collect)
}
}
// For non-sink nodes.
_ => {
if function.nodes[id.idx()].is_control() {
return ProductUseLattice::UnusedBySink;
}
let meet = succ_outs
.iter()
.fold(ProductUseLattice::top(), |acc, latt| {
ProductUseLattice::meet(&acc, latt)
});
if let ProductUseLattice::SpecificUsedBySink(meet_id) = meet {
if meet_id == id {
ProductUseLattice::UsedBySink
} else {
ProductUseLattice::UnusedBySink
}
} else {
meet
}
}
}
});
println!("{:?}", product_uses);
}
...@@ -61,11 +61,11 @@ fn main() { ...@@ -61,11 +61,11 @@ fn main() {
pm.add_pass(hercules_opt::pass::Pass::Verify); pm.add_pass(hercules_opt::pass::Pass::Verify);
} }
add_verified_pass!(pm, args, PhiElim); add_verified_pass!(pm, args, PhiElim);
add_pass!(pm, args, SROA);
add_pass!(pm, args, CCP); add_pass!(pm, args, CCP);
add_pass!(pm, args, DCE); add_pass!(pm, args, DCE);
add_pass!(pm, args, GVN); add_pass!(pm, args, GVN);
add_pass!(pm, args, DCE); add_pass!(pm, args, DCE);
add_pass!(pm, args, SROA);
if args.x_dot { if args.x_dot {
pm.add_pass(hercules_opt::pass::Pass::Xdot(true)); pm.add_pass(hercules_opt::pass::Pass::Xdot(true));
} }
......
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