diff --git a/src/mir.rs b/src/mir.rs index be069eb..6aaaa59 100644 --- a/src/mir.rs +++ b/src/mir.rs @@ -5,6 +5,7 @@ use std::collections::btree_map::Entry; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::fmt::Display; use std::hash::{Hash, Hasher}; +use std::iter::FusedIterator; use std::u32; use itertools::Itertools; @@ -729,22 +730,22 @@ impl NodeRef { self.0 as usize } - fn into_reference_range(self) -> std::ops::Range<(NodeRef, NodeRef)> { - (self, Self::MIN)..(self, Self::MAX) + const fn into_reference_range(self) -> std::ops::Range<(NodeRef, NodeRef)> { + (self.inclusive_start())..(self.inclusive_end()) } #[allow(dead_code)] - fn inclusive_start(self) -> (Self, Self) { + const fn inclusive_start(self) -> (Self, Self) { (self, Self::MIN) } - fn exclusive_start(self) -> (Self, Self) { + const fn exclusive_start(self) -> (Self, Self) { (self, Self::MAX) } #[allow(dead_code)] - fn inclusive_end(self) -> (Self, Self) { + const fn inclusive_end(self) -> (Self, Self) { (self, Self::MAX) } #[allow(dead_code)] - fn exclusive_end(self) -> (Self, Self) { + const fn exclusive_end(self) -> (Self, Self) { (self, Self::MIN) } @@ -772,7 +773,7 @@ impl Mir { self.data[node.index()] = data; } - fn indices(&self) -> impl Iterator { + fn indices(&self) -> impl Iterator + DoubleEndedIterator + FusedIterator { (0..self.nodes.len() as u32).map(|n| NodeRef::from(n)) } } @@ -1369,7 +1370,394 @@ pub mod liveness { use super::*; pub struct Liveness { register_map: BTreeMap, - inference_graph: petgraph::graph::UnGraph<(), ()>, + branches: Branches, + } + + pub struct Branches { + // branches are sequential, so a range, inclusive + branches: Vec<(MirRange, InterferenceGraph)>, + intervals: Vec<(NodeRef, NodeRef)>, + sorted_branches: Vec, + branch_graph: BranchGraph, + } + + type BranchGraph = petgraph::graph::DiGraph<(), ()>; + + impl Branches { + fn dirty_registers_at_node( + &self, + register_map: &BTreeMap, + node: NodeRef, + ) -> Vec { + let others = self + .intervals + .iter() + .filter(|(from, to)| node >= *from && node <= *to) + .filter(|interval| { + Self::interval_intersects_with_node( + &self.sorted_branches, + &self.branch_graph, + **interval, + node, + ) + }) + .filter_map(|(from, _)| register_map.get(from).cloned()); + + let dirty = self + .interference_graph_for_node(node) + .map(|graph| { + graph + .neighbors(node.0.into()) + .filter_map(|n| register_map.get(&NodeRef(n.index() as u32)).cloned()) + }) + .into_iter() + .flatten() + .chain(others) + .collect::>(); + + dirty + } + fn interval_intersects_with_node( + sorted_branches: &Vec, + branch_graph: &BranchGraph, + interval: (NodeRef, NodeRef), + node: NodeRef, + ) -> bool { + let (from, to) = interval; + if node < from || node > to { + return false; + } + + let from_index = sorted_branches + .binary_search_by(|range| range.partial_cmp(&from).unwrap()) + .unwrap(); + let to_index = sorted_branches + .binary_search_by(|range| range.partial_cmp(&to).unwrap()) + .unwrap(); + + let ours_index = sorted_branches + .binary_search_by(|range| range.partial_cmp(&node).unwrap()) + .unwrap(); + + let from_branch = sorted_branches[from_index].start(); + let to_branch = sorted_branches[to_index].start(); + let our_branch = sorted_branches[ours_index].start(); + + if from_branch == our_branch || to_branch == our_branch { + return true; + } + + let mut space = petgraph::algo::DfsSpace::new(&branch_graph); + if petgraph::algo::has_path_connecting( + &branch_graph, + from_branch.0.into(), + our_branch.0.into(), + Some(&mut space), + ) && petgraph::algo::has_path_connecting( + &branch_graph, + our_branch.0.into(), + to_branch.0.into(), + Some(&mut space), + ) { + true + } else { + false + } + } + + pub fn new(mir: &Mir, references: &BTreeSet<(NodeRef, NodeRef)>) -> Self { + let mut sorted_branches = Vec::new(); + let mut branch_graph_edges = Vec::new(); + + let mut start = NodeRef::MIN; + let mut end = start; + for node in mir.indices() { + let (inst, data) = mir.get_node(node); + + match inst { + Inst::Label => { + sorted_branches.push(MirRange::new(start, end)); + start = node; + } + Inst::Jump => { + let to = data.as_node(); + branch_graph_edges.push((start.0, to)); + } + Inst::Branch(_) => { + let (a, b) = data.as_binary(); + branch_graph_edges.push((start.0, a)); + branch_graph_edges.push((start.0, b)); + } + _ => {} + } + end = node; + } + sorted_branches.push(MirRange::new(start, end)); + sorted_branches.sort(); + + let branch_graph = BranchGraph::from_edges(branch_graph_edges); + + eprintln!("branch graph: {branch_graph:?}"); + eprintln!("references: {references:?}"); + + let mut intervals = mir + .indices() + .filter_map(|node| { + references + .range(node.into_reference_range()) + .map(|&(_, to)| to) + .reduce(|acc, to| acc.max(to)) + .map(|max| (node, max)) + }) + // .filter(|(from, _)| mir.is_register(from.0)) + .collect::>(); + intervals.sort(); + + let edges = intervals + .iter() + .flat_map(|(from, to)| { + references + .range(from.exclusive_start()..to.exclusive_end()) + .filter(|(node, _)| { + Self::interval_intersects_with_node( + &sorted_branches, + &branch_graph, + (*from, *to), + *node, + ) + }) + .map(move |(other, _)| (*from, *other)) + }) + .collect::>(); + + eprintln!("intervals: {intervals:#?}"); + eprintln!("edges: {edges:#?}"); + + // build interference graph with mutliple branches. + // BTreeMap + type Edge = (NodeRef, NodeRef); + let mut per_branch_edges = BTreeMap::>::new(); + + for edge in edges.iter() { + let (from, to) = edge; + // find starting label of branch of from and to + let from_branch = sorted_branches + .binary_search_by(|range| range.partial_cmp(from).unwrap()) + .unwrap(); + let to_branch = sorted_branches + .binary_search_by(|range| range.partial_cmp(to).unwrap()) + .unwrap(); + + match per_branch_edges.entry(sorted_branches[from_branch]) { + Entry::Vacant(v) => { + v.insert(vec![*edge]); + } + Entry::Occupied(mut o) => o.get_mut().push(*edge), + } + match per_branch_edges.entry(sorted_branches[to_branch]) { + Entry::Vacant(v) => { + v.insert(vec![*edge]); + } + Entry::Occupied(mut o) => o.get_mut().push(*edge), + } + } + + eprintln!("per_branch_edges: {per_branch_edges:?}"); + + let branches = per_branch_edges + .into_iter() + .map(|(range, edges)| { + ( + range, + InterferenceGraph::from_edges(edges.into_iter().map(|(a, b)| (a.0, b.0))), + ) + }) + .collect::>(); + eprintln!("branches: {branches:#?}"); + + Self { + branches, + intervals, + sorted_branches, + branch_graph, + } + } + + fn does_interfere(&self, node: NodeRef, other: NodeRef) -> bool { + if let Some(index) = self.branch_index_for_node(node) { + if self.branches[index].0.contains(&other) { + return self.branches[index] + .1 + .find_edge(node.0.into(), other.0.into()) + .is_some(); + } + } + false + } + + fn branch_index_for_node(&self, node: NodeRef) -> Option { + self.branches + .binary_search_by(|(range, _)| range.partial_cmp(&node).unwrap()) + .ok() + } + + pub fn interference_graph_for_node(&self, node: NodeRef) -> Option<&InterferenceGraph> { + if let Some(index) = self.branch_index_for_node(node) { + Some(&self.branches[index].1) + } else { + None + } + } + } + + #[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)] + struct MirRange { + start: NodeRef, + inclusive_end: NodeRef, + } + + impl PartialEq for MirRange { + fn eq(&self, other: &NodeRef) -> bool { + self.contains(other) + } + } + + impl PartialOrd for MirRange { + fn partial_cmp(&self, other: &NodeRef) -> Option { + if self.contains(other) { + Some(Ordering::Equal) + } else if &self.inclusive_end < other { + Some(Ordering::Less) + } else { + assert!(&self.start > other); + Some(Ordering::Greater) + } + } + } + + impl MirRange { + fn start(&self) -> NodeRef { + self.start + } + + fn new(start: NodeRef, inclusive_end: NodeRef) -> MirRange { + Self { + start, + inclusive_end, + } + } + fn contains(&self, other: &NodeRef) -> bool { + &self.start <= other && &self.inclusive_end >= other + } + } + + #[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)] + struct LivenessReference { + node: NodeRef, + referenced_by: NodeRef, + } + + pub struct BranchedLivenessBuilder<'a> { + mir: &'a Mir, + // tree of (node, referenced_by) pairs. + // a full range for each node is (node, NodeRef::MIN)..(node, NodeRef::MAX) + // QUESTION: do I want to treat every interval in this tree a separate node to color? + // or just the (node, NodeRef::MIN)..(node, NodeRef::MAX) range? + // references: BTreeSet<(NodeRef, NodeRef)>, + branches: Branches, + // preferred_colors: BTreeMap, + } + + type InterferenceGraph = petgraph::graph::UnGraph<(), ()>; + + impl<'a> BranchedLivenessBuilder<'a> { + pub fn new(mir: &'a Mir) -> Self { + let references = build_reference_tree(mir); + let branches = Branches::new(mir, &references); + Self { + mir, + //references, + branches, + } + } + + fn pre_color_colors(&self) -> BTreeMap { + /* do i want to find colors from the bottom up? + * - on one hand, consumers with in/outs like mul/div are below and want their inputs in some specific register + * - on the other hand, producers like mul/div are above and want to dictate their output registers + * i think the answer is coloring mul/div first, specifically, then collapsing from there. + */ + let mut want_colors = BTreeMap::::new(); + + use Register::*; + let mut in_colors = [r9, r8, rcx, rdx, rdi, rsi].to_vec(); + let mut in_colors_sse = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0].to_vec(); + + for node in self.mir.indices() { + let want_color = match self.mir.get_node(node).0 { + Inst::Parameter(ty) => { + if ty.is_floating() { + in_colors_sse.pop() + } else { + in_colors.pop() + } + } + Inst::ShiftLeft(_) + | Inst::ShiftRightSigned(_) + | Inst::ShiftRightUnsigned(_) => Some(rcx), + Inst::Mul(_) | Inst::Div(_) | Inst::DivSigned(_) => Some(rax), + Inst::Rem(_) | Inst::RemSigned(_) => Some(rdx), + Inst::ReturnValue(ty) => { + if ty.is_floating() { + Some(xmm0) + } else { + Some(rax) + } + } + _ => { + if let Some(dst) = self.mir.dst_node(node) { + // check if there is interference + if !self.branches.does_interfere(node, dst) { + // want the same color as our dst node to avoid copying + want_colors.get(&dst).cloned() + } else { + None + } + } else { + None + } + } + }; + + if let Some(color) = want_color { + want_colors.insert(node, color); + } + } + + want_colors + } + + pub fn build(self) -> Liveness { + let preferred = self.pre_color_colors(); + + let mut colorizer = Colorizer { + mir: &self.mir, + preferred, + graph: &self.branches, + colors: BTreeMap::new(), + }; + + // // prepass: assign preferred colours for in/out values and specific + // // instructions like mul/div which require one operand to be in rax + colorizer.prepass(); + + let register_map = colorizer.colorise(); + + Liveness { + register_map, + branches: self.branches, + } + } } impl Liveness { @@ -1381,23 +1769,19 @@ pub mod liveness { } pub fn get_scratch_register_at_node(&self, node: NodeRef) -> Option { let dirty = self - .inference_graph - .neighbors(node.0.into()) - .filter_map(|n| self.register_map.get(&NodeRef(n.index() as u32))) - .cloned() - .collect::>(); + .branches + .dirty_registers_at_node(&self.register_map, node); Register::SYSV_SCRATCH_GPRS .into_iter() .filter(|c| !dirty.contains(c)) .next() } + pub fn is_register_in_use_at_node(&self, node: NodeRef, reg: Register) -> bool { - self.inference_graph - .neighbors(node.0.into()) - .filter_map(|n| self.register_map.get(&NodeRef(n.index() as u32))) - .find(|&&r| r.parent_reg() == reg.parent_reg()) - .is_some() + self.branches + .dirty_registers_at_node(&self.register_map, node) + .contains(®) } } @@ -1416,26 +1800,23 @@ pub mod liveness { // preferred_color: BTreeMap, } - #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] enum Color { - #[default] - Unassigned, Tentative(Register), Final(Register), } impl Color { - fn color(self) -> Option { + fn color(self) -> Register { match self { - Color::Unassigned => None, - Color::Tentative(color) | Color::Final(color) => Some(color), + Color::Tentative(color) | Color::Final(color) => color, } } } impl<'a> LivenessBuilder<'a> { pub fn new(mir: &'a Mir) -> Self { - let references = Self::build_references(mir); + let references = build_reference_tree(mir); let intervals = mir.indices().filter_map(|node| { let interval = references @@ -1468,42 +1849,6 @@ pub mod liveness { } } - pub fn build(self) -> Liveness { - let preferred = self.pre_color_colors(); - let Self { - mir, - inference_graph, - .. - } = self; - - let mut colorizer = Colorizer { - mir, - preferred, - graph: inference_graph, - colors: BTreeMap::new(), - }; - - // // prepass: assign preferred colours for in/out values and specific - // // instructions like mul/div which require one operand to be in rax - colorizer.prepass(); - - // for &node in references.keys().rev() { - // if !self.nodes[node as usize].result_is_register() { - // continue; - // } - // colorizer.color_node(node.into()); - // } - - let register_map = colorizer.colorise(); - - let Colorizer { graph, .. } = colorizer; - - Liveness { - register_map, - inference_graph: graph, - } - } - fn pre_color_colors(&self) -> BTreeMap { /* do i want to find colors from the bottom up? * - on one hand, consumers with in/outs like mul/div are below and want their inputs in some specific register @@ -1564,94 +1909,20 @@ pub mod liveness { want_colors } + } - fn build_references(mir: &Mir) -> BTreeSet<(NodeRef, NodeRef)> { - let mut references = BTreeSet::new(); - for node in mir.indices() { - Self::reference_node_operands(mir, &mut references, node); - } - - references + fn build_reference_tree(mir: &Mir) -> BTreeSet<(NodeRef, NodeRef)> { + let mut references = BTreeSet::new(); + for node in mir.indices() { + mir.reference_node_operands(node, &mut references); } - fn reference_node_operands( - mir: &Mir, - references: &mut BTreeSet<(NodeRef, NodeRef)>, - node: NodeRef, - ) { - let (inst, data) = mir.get_node(node); - - match inst { - Inst::ReturnValue(_) - | Inst::SignExtend(_) - | Inst::ZeroExtend(_) - | Inst::Negate(_) - | Inst::Not(_) - | Inst::IsZero(_) - | Inst::IsEq(_) - | Inst::IsNeq(_) - | Inst::IsGt(_) - | Inst::IsGe(_) - | Inst::IsLt(_) - | Inst::IsLe(_) - | Inst::Load(_) - | Inst::LoadRegister(_) => { - references.insert((data.as_noderef(), node)); - } - Inst::Branch(condition) => { - references.insert((NodeRef(condition), node)); - } - Inst::Cmp(_) - | Inst::Store(_) - | Inst::Add(_) - | Inst::Sub(_) - | Inst::Mul(_) - | Inst::MulSigned(_) - | Inst::Div(_) - | Inst::DivSigned(_) - | Inst::Rem(_) - | Inst::RemSigned(_) - | Inst::MulSSE(_) - | Inst::DivSSE(_) - | Inst::RemFP(_) - | Inst::BitAnd(_) - | Inst::BitOr(_) - | Inst::BitXOr(_) - | Inst::Phi2(_) - | Inst::ShiftLeft(_) - | Inst::ShiftRightSigned(_) - | Inst::ShiftRightUnsigned(_) => { - let (lhs, rhs) = data.as_binary_noderefs(); - references.insert((lhs, node)); - references.insert((rhs, node)); - } - Inst::GetElementPtr(_) => { - let (src, _) = data.as_binary_noderefs(); - references.insert((src, node)); - } - // these instructions have no inputs - // don't want a wildcard match here to make sure new instructions - // are handled here when they are added. - Inst::Return - | Inst::Jump - | Inst::Parameter(_) - | Inst::Label - | Inst::ConstantBytes - | Inst::ConstantByte - | Inst::ConstantWord - | Inst::ConstantDWord - | Inst::ConstantQWord - | Inst::ConstantSinglePrecision - | Inst::ConstantDoublePrecision - | Inst::ExternRef - | Inst::Alloca => {} - } - } + references } struct Colorizer<'a> { mir: &'a Mir, - graph: petgraph::graph::UnGraph<(), ()>, + graph: &'a Branches, colors: BTreeMap, preferred: BTreeMap, } @@ -1673,7 +1944,7 @@ pub mod liveness { fn prepass(&mut self) { // parameters are first in line let keys = self.preferred.keys().cloned().collect::>(); - for node in keys { + for node in keys.into_iter() { self.precolor_node(node.0.into()); } } @@ -1682,23 +1953,34 @@ pub mod liveness { // prepass: assign preferred colours for in/out values and specific // instructions like mul/div which require one operand to be in rax let node_u32 = node.index() as u32; - let noderef = NodeRef(node_u32); + let node_ref = NodeRef(node_u32); // only apply color here if we have a preference - if let Some(preferred_color) = self.preferred.remove(&noderef) { - let mut clique_colors = self + if let Some(preferred_color) = self.preferred.remove(&node_ref) { + let color_conflict = self .graph - .neighbors(node) - .filter_map(|n| self.colors.get(&NodeRef(n.index() as u32)).cloned()); + .interference_graph_for_node(node_ref) + .map(|graph| { + graph + .neighbors(node) + .filter_map(|n| self.colors.get(&NodeRef(n.index() as u32)).cloned()) + .find(|color| color.color() == preferred_color) + }) + .flatten(); - if clique_colors - .find(|color| color.color() == Some(preferred_color)) - .is_none() - { - self.colors - .insert(noderef, Color::Tentative(preferred_color)); + if color_conflict.is_none() { + match self.colors.entry(node_ref) { + Entry::Vacant(v) => { + v.insert(Color::Tentative(preferred_color)); + } + _ => {} // Entry::Occupied(mut o) => match o.get_mut() { + // Color::Tentative(color) => { + // *color = preferred_color; + // } + // Color::Final(_) => {} + // }, + } } }; - // .chain(self.node_colors(node).into_iter().cloned()); } fn color_node(&mut self, node: petgraph::graph::NodeIndex) { @@ -1707,12 +1989,17 @@ pub mod liveness { // tentatively colored nodes. this results in preferential // coloring depending on the order of the prepass. let node_u32 = node.index() as u32; - let noderef = NodeRef(node_u32); + let node_ref = NodeRef(node_u32); let clique_colors = self .graph - .neighbors(node) - .filter_map(|n| self.colors.get(&NodeRef(n.index() as u32)).cloned()) - .collect::>(); + .interference_graph_for_node(node_ref) + .map(|graph| { + graph + .neighbors(node) + .filter_map(|n| self.colors.get(&NodeRef(n.index() as u32)).cloned()) + .collect::>() + }) + .unwrap_or_default(); let colors = self .node_colors(node) @@ -1721,12 +2008,12 @@ pub mod liveness { .cloned() .collect::>(); - // eprintln!("coloring %{node_u32}:"); - // eprintln!("\twants: {:?}", self.colors.get(&node_u32)); - // eprintln!("\tclique: {clique_colors:?}"); - // eprintln!("\tcandidates: {colors:?}"); + eprintln!("coloring %{node_u32}:"); + eprintln!("\twants: {:?}", self.colors.get(&node_ref)); + eprintln!("\tclique: {clique_colors:?}"); + eprintln!("\tcandidates: {colors:?}"); - let color = match self.colors.entry(noderef) { + let color = match self.colors.entry(node_ref) { Entry::Vacant(v) => { // here we want to first check clique_colors with tentative coloring. let color = colors @@ -1750,13 +2037,13 @@ pub mod liveness { // if this node has a dst node (an operand that is both source and // destination), give it our tentative color - if let Some(dst) = self.mir.dst_node(noderef) { + if let Some(dst) = self.mir.dst_node(node_ref) { _ = self.colors.try_insert(dst, Color::Tentative(color)); } // for any Phi(y_1,y_2, y_n) give y_i the color of Phi // reasonably certain that this will never fail to color all phi nodes the same color. - if let Some(inputs) = self.mir.get_phi_inputs(noderef) { + if let Some(inputs) = self.mir.get_phi_inputs(node_ref) { eprintln!("coloring {inputs:?} {color}"); for node in inputs { _ = self.colors.insert(node, Color::Tentative(color)); @@ -1765,7 +2052,7 @@ pub mod liveness { } fn colorise(&mut self) -> BTreeMap { - for node in self.mir.indices() { + for node in self.mir.indices().rev() { if !self.mir.is_register(node.0) { continue; } @@ -1773,8 +2060,8 @@ pub mod liveness { } self.colors .iter() - .filter_map(|(&node, &c)| match c { - Color::Final(reg) => Some((node, reg)), + .filter_map(|(&n, &c)| match c { + Color::Final(reg) => Some((n, reg)), _ => None, }) .collect() @@ -1783,6 +2070,80 @@ pub mod liveness { } impl Mir { + fn reference_node_operands( + &self, + node: NodeRef, + references: &mut BTreeSet<(NodeRef, NodeRef)>, + ) { + let (inst, data) = self.get_node(node); + + match inst { + Inst::ReturnValue(_) + | Inst::SignExtend(_) + | Inst::ZeroExtend(_) + | Inst::Negate(_) + | Inst::Not(_) + | Inst::IsZero(_) + | Inst::IsEq(_) + | Inst::IsNeq(_) + | Inst::IsGt(_) + | Inst::IsGe(_) + | Inst::IsLt(_) + | Inst::IsLe(_) + | Inst::Load(_) + | Inst::LoadRegister(_) => { + references.insert((data.as_noderef(), node)); + } + Inst::Branch(condition) => { + references.insert((NodeRef(condition), node)); + } + Inst::Cmp(_) + | Inst::Store(_) + | Inst::Add(_) + | Inst::Sub(_) + | Inst::Mul(_) + | Inst::MulSigned(_) + | Inst::Div(_) + | Inst::DivSigned(_) + | Inst::Rem(_) + | Inst::RemSigned(_) + | Inst::MulSSE(_) + | Inst::DivSSE(_) + | Inst::RemFP(_) + | Inst::BitAnd(_) + | Inst::BitOr(_) + | Inst::BitXOr(_) + | Inst::Phi2(_) + | Inst::ShiftLeft(_) + | Inst::ShiftRightSigned(_) + | Inst::ShiftRightUnsigned(_) => { + let (lhs, rhs) = data.as_binary_noderefs(); + references.insert((lhs, node)); + references.insert((rhs, node)); + } + Inst::GetElementPtr(_) => { + let (src, _) = data.as_binary_noderefs(); + references.insert((src, node)); + } + // these instructions have no inputs + // don't want a wildcard match here to make sure new instructions + // are handled here when they are added. + Inst::Return + | Inst::Jump + | Inst::Parameter(_) + | Inst::Label + | Inst::ConstantBytes + | Inst::ConstantByte + | Inst::ConstantWord + | Inst::ConstantDWord + | Inst::ConstantQWord + | Inst::ConstantSinglePrecision + | Inst::ConstantDoublePrecision + | Inst::ExternRef + | Inst::Alloca => {} + } + } + fn get_phi_inputs(&self, node: NodeRef) -> Option> { let (inst, data) = self.get_node(node); match inst { @@ -1858,7 +2219,7 @@ impl Mir { } pub fn build_liveness(&self) -> Liveness { - LivenessBuilder::new(self).build() + liveness::BranchedLivenessBuilder::new(self).build() } } @@ -2082,13 +2443,11 @@ impl Function { write!(w, "{}", self.branches.remove(&NodeRef::MIN).unwrap())?; for (branch, content) in &self.branches { - if name != "main" { - writeln!(w, "{name}_L{}:", branch.0)?; - write!(w, "{content}")?; - } + writeln!(w, ".{name}__L{}:", branch.0)?; + write!(w, "{content}")?; } - writeln!(w, "{name}__epilogue:")?; + writeln!(w, ".{name}__epilogue:")?; writeln!(w, "mov rsp, rbp")?; writeln!(w, "pop rbp")?; @@ -2207,8 +2566,6 @@ impl Mir { let inst = self.nodes[i]; let data = self.data[i]; - self.render_node(func.current_branch(), strings, &liveness, node); - match inst { Inst::Label => { func.create_new_branch(NodeRef(node)); @@ -3160,15 +3517,15 @@ impl Mir { )?; } } - writeln!(func.current_branch(), "jmp {name}__epilogue")?; + writeln!(func.current_branch(), "jmp .{name}__epilogue")?; } Inst::Return => { - writeln!(func.current_branch(), "jmp {name}__epilogue")?; + writeln!(func.current_branch(), "jmp .{name}__epilogue")?; } Inst::Jump => { let lhs = data.as_node(); if lhs != node + 1 { - writeln!(func.current_branch(), "jmp {name}__L{lhs}")?; + writeln!(func.current_branch(), "jmp .{name}__L{lhs}")?; } } Inst::Branch(condition) => { @@ -3179,14 +3536,14 @@ impl Mir { match (lhs, rhs) { _ if lhs == node + 1 => { - writeln!(func.current_branch(), "jz {name}__L{rhs}")?; + writeln!(func.current_branch(), "jz .{name}__L{rhs}")?; } _ if rhs == node + 1 => { - writeln!(func.current_branch(), "jnz {name}__L{lhs}")?; + writeln!(func.current_branch(), "jnz .{name}__L{lhs}")?; } _ => { - writeln!(func.current_branch(), "jnz {name}__L{lhs}")?; - writeln!(func.current_branch(), "jz {name}__L{rhs}")?; + writeln!(func.current_branch(), "jnz .{name}__L{lhs}")?; + writeln!(func.current_branch(), "jz .{name}__L{rhs}")?; } } } diff --git a/tests/legal/if.sea b/tests/legal/if.sea index 0e0c656..da48dd0 100644 --- a/tests/legal/if.sea +++ b/tests/legal/if.sea @@ -1,6 +1,6 @@ fn square_of_greater(a: i32, b: i32) -> i32 { - if (a < b) + if (a > b) a * a else b * b