Skip to content
Draft
100 changes: 68 additions & 32 deletions crates/redpiler/src/backend/direct/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use mchprs_blocks::blocks::{Block, Instrument};
use mchprs_blocks::BlockPos;
use mchprs_world::TickEntry;
use petgraph::visit::EdgeRef;
use petgraph::Direction;
use petgraph::Direction::{self, Outgoing};
use rustc_hash::FxHashMap;
use std::sync::Arc;
use tracing::trace;
Expand All @@ -29,7 +29,8 @@ fn compile_node(
noteblock_info: &mut Vec<(BlockPos, Instrument, u32)>,
forward_links: &mut Vec<ForwardLink>,
stats: &mut FinalGraphStats,
) -> Node {
out_nodes: &mut Vec<Node>,
) {
let node = &graph[node_idx];

const MAX_INPUTS: usize = 255;
Expand Down Expand Up @@ -73,7 +74,7 @@ fn compile_node(
side_inputs.ss_counts[0] += (MAX_INPUTS - side_input_count) as u8;

use crate::compile_graph::NodeType as CNodeType;
let fwd_link_begin = forward_links.len();
forward_links.clear();
if node.ty != CNodeType::Constant {
let new_links = graph
.edges_directed(node_idx, Direction::Outgoing)
Expand All @@ -93,8 +94,7 @@ fn compile_node(
});
forward_links.extend(new_links);
};
let fwd_link_end = forward_links.len();
stats.update_link_count += fwd_link_end - fwd_link_begin;
stats.update_link_count += forward_links.len();

let ty = match &node.ty {
CNodeType::Repeater {
Expand Down Expand Up @@ -128,18 +128,39 @@ fn compile_node(
}
};

Node {
let fwd_link_len = forward_links.len();
assert!(fwd_link_len < u16::MAX as usize);

// Safety: These are simply placeholder values and should never be read
let mut first_links = [ForwardLink::new(unsafe { NodeId::from_index(0) }, false, 0); 5];
let num_first = fwd_link_len.min(first_links.len());
first_links[..num_first].copy_from_slice(&forward_links[..num_first]);

let node = Node {
ty,
default_inputs,
side_inputs,
fwd_link_begin,
fwd_link_end,
fwd_link_len: fwd_link_len as u16,
powered: node.state.powered,
output_power: node.state.output_strength,
locked: node.state.repeater_locked,
pending_tick: false,
changed: false,
is_io: node.is_input || node.is_output,
fwd_links: first_links,
};

let num_link_blocks = node.forward_link_blocks();

out_nodes.reserve(1 + num_link_blocks);
out_nodes.push(node);

let node = out_nodes.last_mut().unwrap();
// Safety: Capacity is previously reserved
// Safety: Node.num_link_blocks allows skipping over the ForwardLink's when iterating
unsafe {
node.forward_links_mut()[num_first..].copy_from_slice(&forward_links[num_first..]);
out_nodes.set_len(out_nodes.len() + num_link_blocks);
}
}

Expand All @@ -150,42 +171,57 @@ pub fn compile(
options: &CompilerOptions,
_monitor: Arc<TaskMonitor>,
) {
backend.blocks = Vec::with_capacity(graph.node_count());

// Create a mapping from compile to backend node indices
let mut nodes_map = FxHashMap::with_capacity_and_hasher(graph.node_count(), Default::default());
let mut nodes_len = 0;
for node in graph.node_indices() {
nodes_map.insert(node, nodes_map.len());
nodes_map.insert(node, nodes_len);

let outgoing = if graph[node].ty == crate::compile_graph::NodeType::Constant {
0
} else {
graph.neighbors_directed(node, Outgoing).count()
};
let extra_nodes = Node::forward_link_blocks_for(outgoing);
nodes_len += 1 + extra_nodes;

let block = graph[node].block.map(|(pos, id)| (pos, Block::from_id(id)));
backend.blocks.push(block);

for _ in 0..extra_nodes {
backend.blocks.push(None);
}
}
let nodes_len = nodes_map.len();

// Lower nodes
let mut stats = FinalGraphStats::default();
let nodes = graph
.node_indices()
.map(|idx| {
compile_node(
&graph,
idx,
nodes_len,
&nodes_map,
&mut backend.noteblock_info,
&mut backend.forward_links,
&mut stats,
)
})
.collect();
let mut nodes = Vec::new();
let mut forward_links = Vec::new();
for idx in graph.node_indices() {
compile_node(
&graph,
idx,
nodes_len,
&nodes_map,
&mut backend.noteblock_info,
&mut forward_links,
&mut stats,
&mut nodes,
);
}
stats.nodes_bytes = nodes_len * std::mem::size_of::<Node>();
trace!("{:#?}", stats);

backend.blocks = graph
.node_weights()
.map(|node| node.block.map(|(pos, id)| (pos, Block::from_id(id))))
.collect();
backend.nodes = Nodes::new(nodes);
assert_eq!(nodes.len(), nodes_len);

backend.nodes = Nodes::new(nodes.into_boxed_slice());

// Create a mapping from block pos to backend NodeId
for i in 0..backend.blocks.len() {
if let Some((pos, _)) = backend.blocks[i] {
backend.pos_map.insert(pos, backend.nodes.get(i));
for i in backend.nodes.ids() {
if let Some((pos, _)) = backend.blocks[i.index()] {
backend.pos_map.insert(pos, backend.nodes.get(i.index()));
}
}

Expand Down
46 changes: 32 additions & 14 deletions crates/redpiler/src/backend/direct/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl Queues {
}
}

#[derive(Default)]
#[derive(Default, Clone)]
struct TickScheduler {
queues_deque: [Queues; Self::NUM_QUEUES],
pos: usize,
Expand Down Expand Up @@ -101,14 +101,14 @@ impl TickScheduler {
}
}

#[derive(Clone)]
enum Event {
NoteBlockPlay { noteblock_id: u16 },
}

#[derive(Default)]
#[derive(Default, Clone)]
pub struct DirectBackend {
nodes: Nodes,
forward_links: Vec<ForwardLink>,
blocks: Vec<Option<(BlockPos, Block)>>,
pos_map: FxHashMap<BlockPos, NodeId>,
scheduler: TickScheduler,
Expand All @@ -129,7 +129,15 @@ impl DirectBackend {
node.powered = powered;
node.output_power = new_power;

for forward_link in &self.forward_links[node.fwd_link_begin..node.fwd_link_end] {
let node = &self.nodes[node_id];

// Safety: node is followed by the correct number of ForwardLink blocks
// Safety: node.fwd_links and node.fwd_link_len are not modified for links's lifetime
let links: &[ForwardLink] = unsafe {
std::slice::from_raw_parts(node.fwd_links.as_ptr(), node.fwd_link_len as usize)
};

for forward_link in links {
let side = forward_link.side();
let distance = forward_link.ss();
let update = forward_link.node();
Expand Down Expand Up @@ -179,8 +187,8 @@ impl JITBackend for DirectBackend {

let nodes = std::mem::take(&mut self.nodes);

for (i, node) in nodes.into_inner().iter().enumerate() {
let Some((pos, block)) = self.blocks[i] else {
for (i, node) in nodes.enumerate() {
let Some((pos, block)) = self.blocks[i.index()] else {
continue;
};
if matches!(node.ty, NodeType::Comparator { .. }) {
Expand All @@ -195,7 +203,6 @@ impl JITBackend for DirectBackend {
}
}

self.forward_links.clear();
self.pos_map.clear();
self.noteblock_info.clear();
self.events.clear();
Expand Down Expand Up @@ -249,8 +256,9 @@ impl JITBackend for DirectBackend {
}
}
}
for (i, node) in self.nodes.inner_mut().iter_mut().enumerate() {
let Some((pos, block)) = &mut self.blocks[i] else {

for (i, node) in self.nodes.enumerate_mut() {
let Some((pos, block)) = &mut self.blocks[i.index()] else {
continue;
};
if node.changed && (!io_only || node.is_io) {
Expand Down Expand Up @@ -352,7 +360,7 @@ fn calculate_comparator_output(mode: ComparatorMode, input_strength: u8, power_o
impl fmt::Display for DirectBackend {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "digraph {{")?;
for (id, node) in self.nodes.inner().iter().enumerate() {
for (id, node) in self.nodes.enumerate() {
if matches!(node.ty, NodeType::Wire) {
continue;
}
Expand All @@ -375,20 +383,30 @@ impl fmt::Display for DirectBackend {
NodeType::Constant => format!("Constant({})", node.output_power),
NodeType::NoteBlock { .. } => "NoteBlock".to_string(),
};
let pos = if let Some((pos, _)) = self.blocks[id] {
let pos = if let Some((pos, _)) = self.blocks[id.index()] {
format!("{}, {}, {}", pos.x, pos.y, pos.z)
} else {
"No Pos".to_string()
};
writeln!(f, " n{} [ label = \"{}\\n({})\" ];", id, label, pos)?;
for link in &self.forward_links[node.fwd_link_begin..node.fwd_link_end] {
writeln!(
f,
" n{} [ label = \"{}\\n({})\" ];",
id.index(),
label,
pos
)?;

for link in self.nodes.forward_link(id) {
let out_index = link.node().index();
let distance = link.ss();
let color = if link.side() { ",color=\"blue\"" } else { "" };
writeln!(
f,
" n{} -> n{} [ label = \"{}\"{} ];",
id, out_index, distance, color
id.index(),
out_index,
distance,
color
)?;
}
}
Expand Down
Loading