mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Add kill, unreachable + switch (#156)
This commit is contained in:
@@ -8,6 +8,7 @@ use super::function::{BlockId, MergeInstruction, Terminator};
|
||||
use crate::FastHashMap;
|
||||
|
||||
use petgraph::{
|
||||
algo::has_path_connecting,
|
||||
graph::{node_index, NodeIndex},
|
||||
visit::EdgeRef,
|
||||
Directed, Direction,
|
||||
@@ -81,9 +82,11 @@ impl FlowGraph {
|
||||
}
|
||||
|
||||
// Branch Edges
|
||||
match self.flow[source_node_index].terminator {
|
||||
let terminator = self.flow[source_node_index].terminator.clone();
|
||||
match terminator {
|
||||
Terminator::Branch { target_id } => {
|
||||
let target_node_index = block_to_node[&target_id];
|
||||
|
||||
self.flow.add_edge(
|
||||
source_node_index,
|
||||
target_node_index,
|
||||
@@ -107,8 +110,28 @@ impl FlowGraph {
|
||||
ControlFlowEdgeType::IfFalse,
|
||||
);
|
||||
}
|
||||
Terminator::Switch { .. } => {
|
||||
// TODO
|
||||
Terminator::Switch {
|
||||
selector: _,
|
||||
default,
|
||||
ref targets,
|
||||
} => {
|
||||
let default_node_index = block_to_node[&default];
|
||||
|
||||
self.flow.add_edge(
|
||||
source_node_index,
|
||||
default_node_index,
|
||||
ControlFlowEdgeType::Forward,
|
||||
);
|
||||
|
||||
for (_, target_block_id) in targets.iter() {
|
||||
let target_node_index = block_to_node[&target_block_id];
|
||||
|
||||
self.flow.add_edge(
|
||||
source_node_index,
|
||||
target_node_index,
|
||||
ControlFlowEdgeType::Forward,
|
||||
);
|
||||
}
|
||||
}
|
||||
Terminator::Return { .. } => {
|
||||
self.flow[source_node_index].ty = Some(ControlFlowNodeType::Return)
|
||||
@@ -120,6 +143,7 @@ impl FlowGraph {
|
||||
};
|
||||
}
|
||||
|
||||
// 2.
|
||||
// Classify Nodes/Edges as one of [Break, Continue, Back]
|
||||
for edge_index in self.flow.edge_indices() {
|
||||
let (node_source_index, node_target_index) =
|
||||
@@ -167,36 +191,103 @@ impl FlowGraph {
|
||||
|
||||
/// Traverses the flow graph and returns a list of Naga's statements.
|
||||
pub fn to_naga(&self) -> Result<crate::Block, Error> {
|
||||
self.naga_traverse(node_index(0))
|
||||
self.naga_traverse(node_index(0), None)
|
||||
}
|
||||
|
||||
fn naga_traverse(&self, node_index: BlockNodeIndex) -> Result<crate::Block, Error> {
|
||||
fn naga_traverse(
|
||||
&self,
|
||||
node_index: BlockNodeIndex,
|
||||
stop_node_index: Option<BlockNodeIndex>,
|
||||
) -> Result<crate::Block, Error> {
|
||||
if let Some(stop_node_index) = stop_node_index {
|
||||
if stop_node_index == node_index {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
}
|
||||
|
||||
let node = &self.flow[node_index];
|
||||
|
||||
match node.ty {
|
||||
Some(ControlFlowNodeType::Header) => {
|
||||
let merge_node_index = self.block_to_node[&node.merge.unwrap().merge_block_id];
|
||||
let mut result = node.block.clone();
|
||||
|
||||
match node.terminator {
|
||||
Terminator::BranchConditional {
|
||||
condition,
|
||||
true_id,
|
||||
false_id,
|
||||
} => {
|
||||
let mut result = node.block.clone();
|
||||
result.push(crate::Statement::If {
|
||||
condition,
|
||||
accept: self.naga_traverse(self.block_to_node[&true_id])?,
|
||||
reject: self.naga_traverse(self.block_to_node[&false_id])?,
|
||||
accept: self.naga_traverse(
|
||||
self.block_to_node[&true_id],
|
||||
Some(merge_node_index),
|
||||
)?,
|
||||
reject: self.naga_traverse(
|
||||
self.block_to_node[&false_id],
|
||||
Some(merge_node_index),
|
||||
)?,
|
||||
});
|
||||
Ok(result)
|
||||
}
|
||||
Terminator::Switch { .. } => {
|
||||
// TODO
|
||||
Ok(node.block.clone())
|
||||
Terminator::Switch {
|
||||
selector,
|
||||
default,
|
||||
ref targets,
|
||||
} => {
|
||||
let mut cases = FastHashMap::default();
|
||||
|
||||
for i in 0..targets.len() {
|
||||
let left_target_node_index = self.block_to_node[&targets[i].1];
|
||||
|
||||
let fallthrough: Option<crate::FallThrough> = if i < targets.len() - 1 {
|
||||
let right_target_node_index = self.block_to_node[&targets[i + 1].1];
|
||||
if has_path_connecting(
|
||||
&self.flow,
|
||||
left_target_node_index,
|
||||
right_target_node_index,
|
||||
None,
|
||||
) {
|
||||
Some(crate::FallThrough {})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
cases.insert(
|
||||
targets[i].0,
|
||||
(
|
||||
self.naga_traverse(
|
||||
left_target_node_index,
|
||||
Some(merge_node_index),
|
||||
)?,
|
||||
fallthrough,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
result.push(crate::Statement::Switch {
|
||||
selector,
|
||||
cases,
|
||||
default: self.naga_traverse(
|
||||
self.block_to_node[&default],
|
||||
Some(merge_node_index),
|
||||
)?,
|
||||
});
|
||||
}
|
||||
_ => Err(Error::InvalidTerminator),
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::InvalidTerminator);
|
||||
}
|
||||
};
|
||||
|
||||
result.extend(self.naga_traverse(merge_node_index, None)?);
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
Some(ControlFlowNodeType::Loop) => {
|
||||
let merge_node_index = self.block_to_node[&node.merge.unwrap().merge_block_id];
|
||||
let continuing: crate::Block = {
|
||||
let continue_edge = self
|
||||
.flow
|
||||
@@ -215,12 +306,14 @@ impl FlowGraph {
|
||||
false_id,
|
||||
} => body.push(crate::Statement::If {
|
||||
condition,
|
||||
accept: self.naga_traverse(self.block_to_node[&true_id])?,
|
||||
reject: self.naga_traverse(self.block_to_node[&false_id])?,
|
||||
accept: self
|
||||
.naga_traverse(self.block_to_node[&true_id], Some(merge_node_index))?,
|
||||
reject: self
|
||||
.naga_traverse(self.block_to_node[&false_id], Some(merge_node_index))?,
|
||||
}),
|
||||
Terminator::Branch { target_id } => {
|
||||
body.extend(self.naga_traverse(self.block_to_node[&target_id])?)
|
||||
}
|
||||
Terminator::Branch { target_id } => body.extend(
|
||||
self.naga_traverse(self.block_to_node[&target_id], Some(merge_node_index))?,
|
||||
),
|
||||
_ => return Err(Error::InvalidTerminator),
|
||||
};
|
||||
|
||||
@@ -235,8 +328,10 @@ impl FlowGraph {
|
||||
false_id,
|
||||
} => result.push(crate::Statement::If {
|
||||
condition,
|
||||
accept: self.naga_traverse(self.block_to_node[&true_id])?,
|
||||
reject: self.naga_traverse(self.block_to_node[&false_id])?,
|
||||
accept: self
|
||||
.naga_traverse(self.block_to_node[&true_id], stop_node_index)?,
|
||||
reject: self
|
||||
.naga_traverse(self.block_to_node[&false_id], stop_node_index)?,
|
||||
}),
|
||||
_ => return Err(Error::InvalidTerminator),
|
||||
};
|
||||
@@ -267,7 +362,9 @@ impl FlowGraph {
|
||||
None => match node.terminator {
|
||||
Terminator::Branch { target_id } => {
|
||||
let mut result = node.block.clone();
|
||||
result.extend(self.naga_traverse(self.block_to_node[&target_id])?);
|
||||
result.extend(
|
||||
self.naga_traverse(self.block_to_node[&target_id], stop_node_index)?,
|
||||
);
|
||||
Ok(result)
|
||||
}
|
||||
_ => Ok(node.block.clone()),
|
||||
|
||||
@@ -1040,6 +1040,14 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
inst.expect(5)?;
|
||||
self.parse_expr_binary_op(expressions, map_binary_operator(op)?)?;
|
||||
}
|
||||
Op::Kill => {
|
||||
inst.expect(1)?;
|
||||
break Terminator::Kill;
|
||||
}
|
||||
Op::Unreachable => {
|
||||
inst.expect(1)?;
|
||||
break Terminator::Unreachable;
|
||||
}
|
||||
Op::Return => {
|
||||
inst.expect(1)?;
|
||||
break Terminator::Return { value: None };
|
||||
@@ -1072,7 +1080,7 @@ impl<I: Iterator<Item = u32>> Parser<I> {
|
||||
let default = self.next()?;
|
||||
|
||||
let mut targets = Vec::new();
|
||||
for _ in 0..inst.wc - 3 {
|
||||
for _ in 0..(inst.wc - 3) / 2 {
|
||||
let literal = self.next()?;
|
||||
let target = self.next()?;
|
||||
targets.push((literal as i32, target));
|
||||
|
||||
Reference in New Issue
Block a user