Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Renamed infos for clarity, consistency, and succinctness #597

Open
wants to merge 17 commits into
base: pfb/extra-info
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions pdg/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ pub fn add_node(
.and_then(|p| event.kind.parent(p))
.map(|(_, nid)| nid),
dest: event_metadata.destination.clone(),
node_info: None,
debug_info: event_metadata.debug_info.clone(),
};

Expand Down
10 changes: 9 additions & 1 deletion pdg/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::{
fmt::{self, Debug, Formatter},
};

use crate::info::NodeInfo;
use crate::util::pad_columns;
use crate::util::ShortOption;

Expand Down Expand Up @@ -119,6 +120,8 @@ pub struct Node {
pub kind: NodeKind,
/// The `Node` that produced the input to this operation.
pub source: Option<NodeId>,
/// Additional information generated from the graphs
pub node_info: Option<NodeInfo>,
/// Any string useful for debugging.
pub debug_info: String,
}
Expand Down Expand Up @@ -147,6 +150,7 @@ impl Node {
dest,
kind,
source,
node_info,
debug_info,
} = self;
let src = ShortOption(source.as_ref());
Expand All @@ -156,9 +160,13 @@ impl Node {
statement_idx,
};
let fn_ = function;
let info = node_info
.as_ref()
.map(|i| i.to_string())
.unwrap_or_default();
write!(
f,
"{kind}{sep}{src}{sep}=>{sep}{dest}{sep}@{sep}{bb_stmt}:{sep}fn {fn_};{sep}{debug_info};"
"{kind}{sep}{src}{sep}=>{sep}{dest}{sep}@{sep}{bb_stmt}:{sep}fn {fn_};{sep}({info}){sep}{debug_info}"
)
}
}
Expand Down
205 changes: 205 additions & 0 deletions pdg/src/info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
use crate::graph::{Graph, GraphId, Graphs, Node, NodeId, NodeKind};
use itertools::Itertools;
use rustc_index::vec::IndexVec;
use rustc_middle::mir::Field;
use std::collections::HashMap;
use std::collections::HashSet;
use std::fmt::{self, Debug, Display, Formatter};

/// The information checked in this struct is whether nodes flow to loads, stores, and offsets (pos
/// and neg), as well as whether they are unique.
/// Uniqueness of node X is determined based on whether there is a node Y which is X's ancestor
/// through copies, fields, and offsets, also is a node Z's ancestor through copies, fields, offsets,
/// where the fields are the same between X and Z, and where Z is chronologically between X and X's last descendent.
/// If such a node exists, X is not unique.
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub struct NodeInfo {
flows_to_store: Option<NodeId>,
flows_to_load: Option<NodeId>,
flows_to_pos_offset: Option<NodeId>,
flows_to_neg_offset: Option<NodeId>,
aliases: Option<NodeId>,
}

impl Display for NodeInfo {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let s = [
("store", self.flows_to_store),
("load", self.flows_to_load),
("+offset", self.flows_to_neg_offset),
("-offset", self.flows_to_neg_offset),
("alias", self.aliases),
]
.into_iter()
.filter_map(|(name, node)| Some((name, node?)))
.format_with(", ", |(name, node), f| f(&format_args!("{name} {node}")));
write!(f, "{}", s)
}
}

fn node_does_mutation(n: &Node) -> bool {
matches!(n.kind, NodeKind::StoreAddr | NodeKind::StoreValue)
}

fn node_does_load(n: &Node) -> bool {
matches!(n.kind, NodeKind::LoadAddr | NodeKind::LoadValue)
}

fn node_does_pos_offset(n: &Node) -> bool {
matches!(n.kind, NodeKind::Offset(x) if x > 0)
}

fn node_does_neg_offset(n: &Node) -> bool {
matches!(n.kind, NodeKind::Offset(x) if x < 0)
}

fn add_children_to_vec(g: &Graph, parents: &HashSet<NodeId>, v: &mut Vec<NodeId>) {
v.extend(
g.nodes
.iter_enumerated()
.filter_map(|(id, node)| Some((id, node.source?)))
.filter(|(_, src_idx)| parents.contains(src_idx))
.map(|(id, _)| id),
);
}

fn check_flows_to_node_kind(
g: &Graph,
n: &NodeId,
node_check: fn(&Node) -> bool,
) -> Option<NodeId> {
let mut seen = HashSet::new();
let mut to_view = vec![*n];
while let Some(node_id_to_check) = to_view.pop() {
if !seen.contains(&node_id_to_check) {
seen.insert(node_id_to_check);
let node_to_check: &Node = g.nodes.get(node_id_to_check).unwrap();
if node_check(node_to_check) {
return Some(node_id_to_check);
} else {
add_children_to_vec(g, &seen, &mut to_view);
}
}
}
None
}

fn greatest_desc(g: &Graph, n: &NodeId) -> NodeId {
let mut desc_seen = HashSet::<NodeId>::new();
let mut to_view = vec![*n];
let mut greatest_index = n.index();
let mut greatest_node_idx = *n;
while let Some(node_id_to_check) = to_view.pop() {
if !desc_seen.contains(&node_id_to_check) {
desc_seen.insert(node_id_to_check);
if node_id_to_check.index() > greatest_index {
greatest_index = node_id_to_check.index();
greatest_node_idx = node_id_to_check;
}
add_children_to_vec(g, &desc_seen, &mut to_view);
}
}
greatest_node_idx
}

/// Finds the highest-up ancestor of the given node n in g which is reached through Copy, Field, and
/// Offset, and returns its index as well as the Fields through which it is reached, in order
/// (the final element is the Field closest to the returned idx)
fn calc_lineage(g: &Graph, n: &NodeId) -> (NodeId, Vec<Field>) {
let mut lineage = Vec::new();
let mut n_idx = *n;
loop {
let node = g.nodes.get(n_idx).unwrap();
let parent = match node.source {
None => break,
Some(p) => p,
};
n_idx = match node.kind {
NodeKind::Offset(_) => parent,
NodeKind::Copy => parent,
NodeKind::Field(f) => {
lineage.push(f);
parent
}
_ => break,
};
}
(n_idx, lineage)
}

/// Looks for a node which proves that the given node n is not unique. If any is found, it's
/// immediately returned (no guarantee of which is returned if multiple violate the uniqueness conditions);
/// otherwise None is returned.
pub fn check_whether_rules_obeyed(g: &Graph, n: &NodeId) -> Option<NodeId> {
let (oldest_ancestor, oldest_lineage) = calc_lineage(g, n);
let youngest_descendent = greatest_desc(g, n);
let mut to_view = vec![(oldest_ancestor, oldest_lineage)];
while let Some((cur_node_id, mut lineage)) = to_view.pop() {
if cur_node_id == *n {
continue;
}
if let NodeKind::Field(f) = g.nodes.get(cur_node_id).unwrap().kind {
match lineage.pop() {
None => continue,
Some(top_of_vec) => {
if top_of_vec != f {
continue;
}
}
}
}
if lineage.is_empty()
&& cur_node_id.index() >= n.index()
&& cur_node_id.index() <= youngest_descendent.index()
{
return Some(cur_node_id);
}
to_view.extend(
g.nodes
.iter_enumerated()
.filter_map(|(id, node)| Some((id, node.source?)))
.filter(|(_, src_idx)| *src_idx == cur_node_id)
.map(|(id, _)| (id, lineage.clone())),
);
}
None
}

/// Takes a list of graphs, creates a NodeInfo object for each node in each graph, filling it with
/// the correct flow information.
pub fn augment_with_info(pdg: &mut Graphs) {
let gs: &mut IndexVec<GraphId, Graph> = &mut pdg.graphs;
for g in gs.iter_mut() {
let mut idx_flow_to_store = HashMap::new();
let mut idx_flow_to_load = HashMap::new();
let mut idx_flow_to_pos_offset = HashMap::new();
let mut idx_flow_to_neg_offset = HashMap::new();
let mut idx_aliases = HashMap::new();
for (idx, _) in g.nodes.iter_enumerated() {
if let Some(descmutidx) = check_flows_to_node_kind(g, &idx, node_does_mutation) {
idx_flow_to_store.insert(idx, descmutidx);
}
if let Some(descuseidx) = check_flows_to_node_kind(g, &idx, node_does_load) {
idx_flow_to_load.insert(idx, descuseidx);
}
if let Some(descposoidx) = check_flows_to_node_kind(g, &idx, node_does_pos_offset) {
idx_flow_to_pos_offset.insert(idx, descposoidx);
}
if let Some(descnegoidx) = check_flows_to_node_kind(g, &idx, node_does_neg_offset) {
idx_flow_to_neg_offset.insert(idx, descnegoidx);
}
if let Some(non_unique_idx) = check_whether_rules_obeyed(g, &idx) {
idx_aliases.insert(idx, non_unique_idx);
}
}
for (idx, node) in g.nodes.iter_enumerated_mut() {
node.node_info = Some(NodeInfo {
flows_to_store: idx_flow_to_store.remove(&idx),
flows_to_load: idx_flow_to_load.remove(&idx),
flows_to_pos_offset: idx_flow_to_pos_offset.remove(&idx),
flows_to_neg_offset: idx_flow_to_pos_offset.remove(&idx),
aliases: idx_aliases.remove(&idx),
})
}
}
}
5 changes: 4 additions & 1 deletion pdg/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ extern crate rustc_target;
mod assert;
mod builder;
mod graph;
mod info;
mod query;
mod util;

use builder::{construct_pdg, read_event_log};
use clap::{Parser, ValueEnum};
use color_eyre::eyre;
use info::augment_with_info;
use std::{
collections::HashSet,
fmt::{self, Display, Formatter},
Expand Down Expand Up @@ -91,7 +93,8 @@ fn main() -> eyre::Result<()> {
}
}

let pdg = construct_pdg(&events, metadata);
let mut pdg = construct_pdg(&events, metadata);
augment_with_info(&mut pdg);
pdg.assert_all_tests();

if should_print(ToPrint::LatestAssignments) {
Expand Down
Loading