Skip to content

Commit

Permalink
Fix DCA for generic functions.
Browse files Browse the repository at this point in the history
Closes #3671.
  • Loading branch information
tritao committed Feb 1, 2023
1 parent 7f65d7e commit 3fddf4a
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 42 deletions.
6 changes: 2 additions & 4 deletions sway-core/src/control_flow_analysis/analyze_return_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl<'cfg> ControlFlowGraph<'cfg> {
pub(crate) fn analyze_return_paths(&self, engines: Engines<'_>) -> Vec<CompileError> {
let mut errors = vec![];
for (
name,
(name, _sig),
FunctionNamespaceEntry {
entry_point,
exit_point,
Expand Down Expand Up @@ -305,9 +305,7 @@ fn connect_typed_fn_decl<'eng: 'cfg, 'cfg>(
.to_typeinfo(fn_decl.return_type, &fn_decl.return_type_span)
.unwrap_or_else(|_| TypeInfo::Tuple(Vec::new())),
};
graph
.namespace
.insert_function(fn_decl.name.clone(), namespace_entry);
graph.namespace.insert_function(fn_decl, namespace_entry);
Ok(())
}

Expand Down
60 changes: 47 additions & 13 deletions sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,7 @@ impl<'cfg> ControlFlowGraph<'cfg> {
&leaves,
exit_node,
tree_type,
NodeConnectionOptions {
force_struct_fields_connection: false,
},
NodeConnectionOptions::default(),
)?;

leaves = l_leaves;
Expand Down Expand Up @@ -188,7 +186,7 @@ fn collect_entry_points(

/// This struct is used to pass node connection further down the tree as
/// we are processing AST nodes.
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Default)]
struct NodeConnectionOptions {
/// When this is enabled, connect struct fields to the struct itself,
/// thus making all struct fields considered as being used in the graph.
Expand Down Expand Up @@ -444,7 +442,6 @@ fn connect_impl_trait<'eng: 'cfg, 'cfg>(
graph.add_edge(entry_node, node_ix, "".into());
}
Some(trait_decl_node) => {
graph.add_edge_from_entry(entry_node, "".into());
graph.add_edge(entry_node, trait_decl_node, "".into());
}
};
Expand Down Expand Up @@ -687,9 +684,7 @@ fn connect_typed_fn_decl<'eng: 'cfg, 'cfg>(
return_type: ty,
};

graph
.namespace
.insert_function(fn_decl.name.clone(), namespace_entry);
graph.namespace.insert_function(fn_decl, namespace_entry);

connect_fn_params_struct_enums(engines, fn_decl, graph, entry_node)?;
Ok(())
Expand Down Expand Up @@ -824,11 +819,50 @@ fn connect_expression<'eng: 'cfg, 'cfg>(
} => {
let fn_decl = decl_engine.get_function(function_decl_id.clone(), &expression_span)?;
let mut is_external = false;
// println!(
// "connect_expression fn_decl {:?} {:?}",
// fn_decl.name,
// function_decl_id.clone()
// );

// in the case of monomorphized functions, first check if we already have a node for
// it in the namespace. if not then we need to check to see if the namespace contains
// the decl id parents (the original generic non monomorphized decl id).
let mut exists = false;
let parents = decl_engine.find_all_parents(engines, function_decl_id.clone());
for parent in parents {
if let Ok(parent) = decl_engine.get_function(parent.clone(), &expression_span) {
exists |= graph.namespace.get_function(&parent).is_some();
}
}

// find the function in the namespace
let (fn_entrypoint, fn_exit_point) = graph
.namespace
.get_function(&fn_decl.name)
.cloned()
let fn_namespace_entry = graph.namespace.get_function(&fn_decl).cloned();

let mut leaves = leaves.to_vec();

// if the parent node exists in this module, then add the monomorphized version
// to the graph.
if fn_namespace_entry.is_none() && exists {
let (l_leaves, _new_exit_node) = connect_node(
engines,
&ty::TyAstNode {
content: ty::TyAstNodeContent::Declaration(
ty::TyDeclaration::FunctionDeclaration(function_decl_id.clone()),
),
span: expression_span.clone(),
},
graph,
&leaves,
exit_node,
tree_type,
NodeConnectionOptions::default(),
)?;

leaves = l_leaves;
}

let (fn_entrypoint, fn_exit_point) = fn_namespace_entry
.map(
|FunctionNamespaceEntry {
entry_point,
Expand Down Expand Up @@ -860,7 +894,7 @@ fn connect_expression<'eng: 'cfg, 'cfg>(
}

for leaf in leaves {
graph.add_edge(*leaf, fn_entrypoint, label.into());
graph.add_edge(leaf, fn_entrypoint, label.into());
}

// save the existing options value to restore after handling the arguments
Expand Down
14 changes: 1 addition & 13 deletions sway-core/src/control_flow_analysis/flow_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ pub type ExitPoint = NodeIndex;
pub struct ControlFlowGraph<'cfg> {
pub(crate) graph: Graph<'cfg>,
pub(crate) entry_points: Vec<NodeIndex>,
pub(crate) pending_entry_points_edges: Vec<(NodeIndex, ControlFlowGraphEdge)>,
pub(crate) namespace: ControlFlowNamespace,
pub(crate) decls: HashMap<IdentUnique, NodeIndex>,
}
Expand Down Expand Up @@ -167,9 +166,6 @@ impl<'cfg> std::fmt::Debug for ControlFlowGraphNode<'cfg> {
}

impl<'cfg> ControlFlowGraph<'cfg> {
pub(crate) fn add_edge_from_entry(&mut self, to: NodeIndex, label: ControlFlowGraphEdge) {
self.pending_entry_points_edges.push((to, label));
}
pub(crate) fn add_node<'eng: 'cfg>(
&mut self,
engines: Engines<'eng>,
Expand All @@ -179,6 +175,7 @@ impl<'cfg> ControlFlowGraph<'cfg> {
let ident_opt = node.get_decl_ident(decl_engine);
let node_index = self.graph.add_node(node);
if let Some(ident) = ident_opt {
//println!("CFG add_node: {:?}", ident);
self.decls.insert(ident.into(), node_index);
}
node_index
Expand All @@ -192,15 +189,6 @@ impl<'cfg> ControlFlowGraph<'cfg> {
self.graph.add_edge(from, to, edge)
}

pub(crate) fn connect_pending_entry_edges(&mut self) {
for entry in &self.entry_points {
for (to, label) in &self.pending_entry_points_edges {
self.graph.add_edge(*entry, *to, label.clone());
}
}
self.pending_entry_points_edges.clear();
}

pub(crate) fn get_node_from_decl(
&self,
engines: Engines<'_>,
Expand Down
31 changes: 23 additions & 8 deletions sway-core/src/control_flow_analysis/flow_graph/namespace.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use super::{EntryPoint, ExitPoint};
use crate::{
language::{ty, CallPath},
language::{
ty::{self, TyFunctionDeclaration, TyFunctionSig},
CallPath,
},
type_system::TypeInfo,
Ident,
};
Expand Down Expand Up @@ -32,7 +35,7 @@ pub(crate) struct StructNamespaceEntry {
/// of scope at this point, as that would have been caught earlier and aborted the compilation
/// process.
pub struct ControlFlowNamespace {
pub(crate) function_namespace: HashMap<IdentUnique, FunctionNamespaceEntry>,
pub(crate) function_namespace: HashMap<(IdentUnique, TyFunctionSig), FunctionNamespaceEntry>,
pub(crate) enum_namespace: HashMap<IdentUnique, (NodeIndex, HashMap<Ident, NodeIndex>)>,
pub(crate) trait_namespace: HashMap<CallPath, NodeIndex>,
/// This is a mapping from trait name to method names and their node indexes
Expand All @@ -45,13 +48,25 @@ pub struct ControlFlowNamespace {
}

impl ControlFlowNamespace {
pub(crate) fn get_function(&self, ident: &Ident) -> Option<&FunctionNamespaceEntry> {
let ident: IdentUnique = ident.into();
self.function_namespace.get(&ident)
}
pub(crate) fn insert_function(&mut self, ident: Ident, entry: FunctionNamespaceEntry) {
pub(crate) fn get_function(
&self,
fn_decl: &TyFunctionDeclaration,
) -> Option<&FunctionNamespaceEntry> {
//println!("get_function ident {:#?}", ident.span);
let ident: IdentUnique = fn_decl.name.clone().into();
self.function_namespace
.get(&(ident, TyFunctionSig::from_fn_decl(fn_decl)))
}
pub(crate) fn insert_function(
&mut self,
fn_decl: &ty::TyFunctionDeclaration,
entry: FunctionNamespaceEntry,
) {
let ident = &fn_decl.name;
//println!("insert function ident {:#?}", ident.span);
let ident: IdentUnique = ident.into();
self.function_namespace.insert(ident, entry);
self.function_namespace
.insert((ident, TyFunctionSig::from_fn_decl(fn_decl)), entry);
}
pub(crate) fn get_constant(&self, ident: &Ident) -> Option<&NodeIndex> {
self.const_namespace.get(ident)
Expand Down
19 changes: 19 additions & 0 deletions sway-core/src/language/ty/declaration/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,3 +372,22 @@ impl TyFunctionParameter {
self.name.as_str() == "self"
}
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TyFunctionSig {
pub return_type: TypeId,
pub parameters: Vec<TypeId>,
}

impl TyFunctionSig {
pub fn from_fn_decl(fn_decl: &TyFunctionDeclaration) -> Self {
Self {
return_type: fn_decl.return_type,
parameters: fn_decl
.parameters
.iter()
.map(|p| p.type_id)
.collect::<Vec<_>>(),
}
}
}
6 changes: 2 additions & 4 deletions sway-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ fn module_dead_code_analysis<'eng: 'cfg, 'cfg>(
module_dead_code_analysis(engines, &submodule.module, &tree_type, graph)
})
});
let res = submodules_res.flat_map(|()| {
submodules_res.flat_map(|()| {
ControlFlowGraph::append_module_to_dead_code_graph(
engines,
&module.all_nodes,
Expand All @@ -795,9 +795,7 @@ fn module_dead_code_analysis<'eng: 'cfg, 'cfg>(
)
.map(|_| ok((), vec![], vec![]))
.unwrap_or_else(|error| err(vec![], vec![error]))
});
graph.connect_pending_entry_edges();
res
})
}

fn return_path_analysis(engines: Engines<'_>, program: &ty::TyProgram) -> Vec<CompileError> {
Expand Down

0 comments on commit 3fddf4a

Please sign in to comment.