Skip to content

Commit

Permalink
feat(semantic/cfg): propagate unreachable edges through subgraphs. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
rzvxa committed Jun 13, 2024
1 parent 6380b0a commit ddab23c
Show file tree
Hide file tree
Showing 22 changed files with 100 additions and 60 deletions.
11 changes: 8 additions & 3 deletions crates/oxc_semantic/examples/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use oxc_allocator::Allocator;
use oxc_parser::Parser;
use oxc_semantic::{DebugDot, DisplayDot, EdgeType, SemanticBuilder};
use oxc_span::SourceType;
use petgraph::dot::{Config, Dot};
use petgraph::{
dot::{Config, Dot},
visit::EdgeRef,
};

// Instruction:
// 1. create a `test.js`,
Expand Down Expand Up @@ -91,8 +94,10 @@ fn main() -> std::io::Result<()> {
&|_graph, edge| {
let weight = edge.weight();
let label = format!("label = \"{weight:?}\"");
if matches!(weight, EdgeType::Unreachable) {
format!("{label}, style = \"dotted\"")
if matches!(weight, EdgeType::Unreachable)
|| semantic.semantic.cfg().basic_block(edge.source()).unreachable
{
format!("{label}, style = \"dotted\" ")
} else {
label
}
Expand Down
29 changes: 28 additions & 1 deletion crates/oxc_semantic/src/control_flow/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::ReturnInstructionKind;
use context::Ctx;

pub use context::{CtxCursor, CtxFlags};
use petgraph::Direction;

use super::{
AstNodeId, BasicBlock, BasicBlockId, CompactStr, ControlFlowGraph, EdgeType, ErrorEdgeKind,
Expand Down Expand Up @@ -56,6 +57,17 @@ impl<'a> ControlFlowGraphBuilder<'a> {
self.basic_block_mut(self.current_node_ix)
}

/// # Panics
pub fn basic_block(&self, basic_block: BasicBlockId) -> &BasicBlock {
let idx = *self
.graph
.node_weight(basic_block)
.expect("expected `self.current_node_ix` to be a valid node index in self.graph");
self.basic_blocks
.get(idx)
.expect("expected `self.current_node_ix` to be a valid node index in self.graph")
}

/// # Panics
pub fn basic_block_mut(&mut self, basic_block: BasicBlockId) -> &mut BasicBlock {
let idx = *self
Expand Down Expand Up @@ -99,6 +111,20 @@ impl<'a> ControlFlowGraphBuilder<'a> {
}

pub fn add_edge(&mut self, a: BasicBlockId, b: BasicBlockId, weight: EdgeType) {
if matches!(weight, EdgeType::NewFunction) {
self.basic_block_mut(b).unreachable = false;
} else if self.basic_block(a).unreachable {
if self.graph.edges_directed(b, Direction::Incoming).count() == 0 {
self.basic_block_mut(b).unreachable = true;
}
} else if !self
.basic_block(b)
.instructions()
.iter()
.any(|it| matches!(it, Instruction { kind: InstructionKind::Unreachable, .. }))
{
self.basic_block_mut(b).unreachable = false;
}
self.graph.add_edge(a, b, weight);
}

Expand Down Expand Up @@ -193,12 +219,13 @@ impl<'a> ControlFlowGraphBuilder<'a> {
pub fn append_unreachable(&mut self) {
let current_node_ix = self.current_node_ix;
let basic_block_with_unreachable_graph_ix = self.new_basic_block_normal();
self.push_instruction(InstructionKind::Unreachable, None);
self.current_basic_block().unreachable = true;
self.add_edge(
current_node_ix,
basic_block_with_unreachable_graph_ix,
EdgeType::Unreachable,
);
self.push_instruction(InstructionKind::Unreachable, None);
}

#[inline]
Expand Down
13 changes: 10 additions & 3 deletions crates/oxc_semantic/src/control_flow/dot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ use oxc_ast::{
AstKind,
};
use oxc_syntax::node::AstNodeId;
use petgraph::dot::{Config, Dot};
use petgraph::{
dot::{Config, Dot},
visit::EdgeRef,
};

use crate::{
AstNode, AstNodes, BasicBlock, ControlFlowGraph, EdgeType, Instruction, InstructionKind,
Expand Down Expand Up @@ -56,7 +59,9 @@ impl DisplayDot for ControlFlowGraph {
&|_graph, edge| {
let weight = edge.weight();
let label = format!("label = \"{weight:?}\" ");
if matches!(weight, EdgeType::Unreachable) {
if matches!(weight, EdgeType::Unreachable)
|| self.basic_block(edge.source()).unreachable
{
format!("{label}, style = \"dotted\" ")
} else {
label
Expand Down Expand Up @@ -115,7 +120,9 @@ impl DebugDot for ControlFlowGraph {
&|_graph, edge| {
let weight = edge.weight();
let label = format!("label = \"{weight:?}\" ");
if matches!(weight, EdgeType::Unreachable) {
if matches!(weight, EdgeType::Unreachable)
|| self.basic_block(edge.source()).unreachable
{
format!("{label}, style = \"dotted\" ")
} else {
label
Expand Down
3 changes: 2 additions & 1 deletion crates/oxc_semantic/src/control_flow/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,12 @@ pub enum CallType {
#[derive(Debug)]
pub struct BasicBlock {
pub instructions: Vec<Instruction>,
pub unreachable: bool,
}

impl BasicBlock {
fn new() -> Self {
BasicBlock { instructions: Vec::new() }
BasicBlock { instructions: Vec::new(), unreachable: false }
}

pub fn instructions(&self) -> &Vec<Instruction> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ digraph {
2 [ label = "unreachable" ]
3 [ label = "" ]
1 -> 0 [ label = "Error(Implicit)" ]
2 -> 0 [ label = "Error(Implicit)" ]
2 -> 0 [ label = "Error(Implicit)" , style = "dotted" ]
1 -> 2 [ label = "Unreachable" , style = "dotted" ]
3 -> 0 [ label = "Error(Implicit)" ]
2 -> 3 [ label = "Normal" ]
2 -> 3 [ label = "Normal" , style = "dotted" ]
1 -> 3 [ label = "Jump" ]
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ digraph {
1 -> 0 [ label = "Error(Implicit)" ]
3 -> 2 [ label = "Error(Implicit)" ]
1 -> 3 [ label = "NewFunction" ]
4 -> 2 [ label = "Error(Implicit)" ]
4 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
3 -> 4 [ label = "Unreachable" , style = "dotted" ]
5 -> 0 [ label = "Error(Implicit)" ]
1 -> 5 [ label = "Normal" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ digraph {
6 -> 2 [ label = "Error(Implicit)" ]
4 -> 6 [ label = "Normal" ]
7 -> 2 [ label = "Error(Implicit)" ]
8 -> 2 [ label = "Error(Implicit)" ]
8 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
7 -> 8 [ label = "Unreachable" , style = "dotted" ]
9 -> 2 [ label = "Error(Implicit)" ]
9 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
10 -> 2 [ label = "Error(Implicit)" ]
6 -> 7 [ label = "Normal" ]
8 -> 9 [ label = "Normal" ]
9 -> 10 [ label = "Normal" ]
9 -> 7 [ label = "Backedge" ]
8 -> 9 [ label = "Normal" , style = "dotted" ]
9 -> 10 [ label = "Normal" , style = "dotted" ]
9 -> 7 [ label = "Backedge" , style = "dotted" ]
7 -> 10 [ label = "Jump" ]
11 -> 2 [ label = "Error(Implicit)" ]
3 -> 5 [ label = "Normal" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ digraph {
1 -> 0 [ label = "Error(Implicit)" ]
3 -> 2 [ label = "Error(Implicit)" ]
1 -> 3 [ label = "NewFunction" ]
4 -> 2 [ label = "Error(Implicit)" ]
4 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
3 -> 4 [ label = "Unreachable" , style = "dotted" ]
5 -> 0 [ label = "Error(Implicit)" ]
1 -> 5 [ label = "Normal" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,18 @@ digraph {
4 -> 6 [ label = "Normal" ]
5 -> 6 [ label = "Normal" ]
7 -> 2 [ label = "Error(Implicit)" ]
8 -> 2 [ label = "Error(Implicit)" ]
8 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
7 -> 8 [ label = "Unreachable" , style = "dotted" ]
9 -> 2 [ label = "Error(Implicit)" ]
10 -> 2 [ label = "Error(Implicit)" ]
10 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
9 -> 10 [ label = "Unreachable" , style = "dotted" ]
11 -> 2 [ label = "Error(Implicit)" ]
11 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
3 -> 4 [ label = "Normal" ]
8 -> 11 [ label = "Normal" ]
8 -> 11 [ label = "Normal" , style = "dotted" ]
6 -> 7 [ label = "Jump" ]
3 -> 9 [ label = "Normal" ]
10 -> 11 [ label = "Normal" ]
12 -> 2 [ label = "Error(Implicit)" ]
10 -> 11 [ label = "Normal" , style = "dotted" ]
12 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
11 -> 12 [ label = "Unreachable" , style = "dotted" ]
13 -> 0 [ label = "Error(Implicit)" ]
1 -> 13 [ label = "Normal" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@ digraph {
6 -> 2 [ label = "Error(Implicit)" ]
7 -> 2 [ label = "Error(Implicit)" ]
8 -> 2 [ label = "Error(Implicit)" ]
9 -> 2 [ label = "Error(Implicit)" ]
9 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
8 -> 9 [ label = "Unreachable" , style = "dotted" ]
10 -> 2 [ label = "Error(Implicit)" ]
11 -> 2 [ label = "Error(Implicit)" ]
12 -> 2 [ label = "Error(Implicit)" ]
13 -> 2 [ label = "Error(Implicit)" ]
13 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
12 -> 13 [ label = "Unreachable" , style = "dotted" ]
14 -> 2 [ label = "Error(Implicit)" ]
10 -> 11 [ label = "Normal" ]
13 -> 14 [ label = "Normal" ]
13 -> 14 [ label = "Normal" , style = "dotted" ]
11 -> 12 [ label = "Jump" ]
10 -> 14 [ label = "Normal" ]
15 -> 2 [ label = "Error(Implicit)" ]
6 -> 7 [ label = "Normal" ]
9 -> 15 [ label = "Normal" ]
9 -> 15 [ label = "Normal" , style = "dotted" ]
7 -> 8 [ label = "Jump" ]
6 -> 10 [ label = "Normal" ]
14 -> 15 [ label = "Normal" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ digraph {
2 -> 4 [ label = "Normal" ]
5 -> 0 [ label = "Error(Implicit)" ]
6 -> 0 [ label = "Error(Implicit)" ]
7 -> 0 [ label = "Error(Implicit)" ]
7 -> 0 [ label = "Error(Implicit)" , style = "dotted" ]
6 -> 7 [ label = "Unreachable" , style = "dotted" ]
8 -> 0 [ label = "Error(Implicit)" ]
4 -> 5 [ label = "Normal" ]
7 -> 8 [ label = "Normal" ]
7 -> 8 [ label = "Normal" , style = "dotted" ]
5 -> 6 [ label = "Jump" ]
4 -> 8 [ label = "Normal" ]
9 -> 0 [ label = "Error(Implicit)" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,20 @@ digraph {
1 -> 3 [ label = "NewFunction" ]
5 -> 2 [ label = "Error(Implicit)" ]
5 -> 4 [ label = "Finalize" ]
6 -> 2 [ label = "Error(Implicit)" ]
6 -> 4 [ label = "Finalize" ]
6 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
6 -> 4 [ label = "Finalize" , style = "dotted" ]
5 -> 6 [ label = "Unreachable" , style = "dotted" ]
7 -> 2 [ label = "Error(Implicit)" ]
4 -> 7 [ label = "Normal" ]
8 -> 2 [ label = "Error(Implicit)" ]
8 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
7 -> 8 [ label = "Unreachable" , style = "dotted" ]
9 -> 2 [ label = "Error(Implicit)" ]
9 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
3 -> 5 [ label = "Normal" ]
8 -> 9 [ label = "Join" ]
8 -> 9 [ label = "Join" , style = "dotted" ]
10 -> 2 [ label = "Error(Implicit)" ]
9 -> 10 [ label = "Normal" ]
9 -> 10 [ label = "Normal" , style = "dotted" ]
7 -> 10 [ label = "Jump" ]
11 -> 2 [ label = "Error(Implicit)" ]
11 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
10 -> 11 [ label = "Unreachable" , style = "dotted" ]
12 -> 0 [ label = "Error(Implicit)" ]
1 -> 12 [ label = "Normal" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ digraph {
1 -> 0 [ label = "Error(Implicit)" ]
3 -> 2 [ label = "Error(Implicit)" ]
1 -> 3 [ label = "NewFunction" ]
4 -> 2 [ label = "Error(Implicit)" ]
4 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
3 -> 4 [ label = "Unreachable" , style = "dotted" ]
5 -> 2 [ label = "Error(Implicit)" ]
5 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
4 -> 5 [ label = "Unreachable" , style = "dotted" ]
6 -> 0 [ label = "Error(Implicit)" ]
1 -> 6 [ label = "Normal" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ digraph {
1 -> 0 [ label = "Error(Implicit)" ]
3 -> 2 [ label = "Error(Implicit)" ]
1 -> 3 [ label = "NewFunction" ]
4 -> 2 [ label = "Error(Implicit)" ]
4 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
3 -> 4 [ label = "Unreachable" , style = "dotted" ]
5 -> 2 [ label = "Error(Implicit)" ]
5 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
4 -> 5 [ label = "Unreachable" , style = "dotted" ]
6 -> 0 [ label = "Error(Implicit)" ]
1 -> 6 [ label = "Normal" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ digraph {
1 -> 0 [ label = "Error(Implicit)" ]
3 -> 2 [ label = "Error(Implicit)" ]
1 -> 3 [ label = "NewFunction" ]
4 -> 2 [ label = "Error(Implicit)" ]
4 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
3 -> 4 [ label = "Unreachable" , style = "dotted" ]
5 -> 0 [ label = "Error(Implicit)" ]
1 -> 5 [ label = "Normal" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ digraph {
1 -> 0 [ label = "Error(Implicit)" ]
3 -> 2 [ label = "Error(Implicit)" ]
1 -> 3 [ label = "NewFunction" ]
4 -> 2 [ label = "Error(Implicit)" ]
4 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
3 -> 4 [ label = "Unreachable" , style = "dotted" ]
5 -> 0 [ label = "Error(Implicit)" ]
1 -> 5 [ label = "Normal" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ digraph {
1 -> 0 [ label = "Error(Implicit)" ]
3 -> 2 [ label = "Error(Implicit)" ]
1 -> 3 [ label = "NewFunction" ]
4 -> 2 [ label = "Error(Implicit)" ]
4 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
3 -> 4 [ label = "Unreachable" , style = "dotted" ]
5 -> 0 [ label = "Error(Implicit)" ]
1 -> 5 [ label = "Normal" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ digraph {
1 -> 0 [ label = "Error(Implicit)" ]
3 -> 2 [ label = "Error(Implicit)" ]
1 -> 3 [ label = "NewFunction" ]
4 -> 2 [ label = "Error(Implicit)" ]
4 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
3 -> 4 [ label = "Unreachable" , style = "dotted" ]
5 -> 0 [ label = "Error(Implicit)" ]
1 -> 5 [ label = "Normal" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ digraph {
4 -> 0 [ label = "Error(Implicit)" ]
5 -> 0 [ label = "Error(Implicit)" ]
4 -> 5 [ label = "Jump" ]
6 -> 0 [ label = "Error(Implicit)" ]
6 -> 0 [ label = "Error(Implicit)" , style = "dotted" ]
5 -> 6 [ label = "Unreachable" , style = "dotted" ]
7 -> 0 [ label = "Error(Implicit)" ]
8 -> 0 [ label = "Error(Implicit)" ]
7 -> 8 [ label = "Jump" ]
4 -> 7 [ label = "Normal" ]
6 -> 7 [ label = "Normal" ]
6 -> 7 [ label = "Normal" , style = "dotted" ]
3 -> 4 [ label = "Normal" ]
3 -> 7 [ label = "Normal" ]
9 -> 0 [ label = "Error(Implicit)" ]
Expand Down
Loading

0 comments on commit ddab23c

Please sign in to comment.