register allocator refactor
This commit is contained in:
		
							parent
							
								
									16399192b3
								
							
						
					
					
						commit
						06b1ec1763
					
				
							
								
								
									
										274
									
								
								src/mir.rs
									
									
									
									
									
								
							
							
						
						
									
										274
									
								
								src/mir.rs
									
									
									
									
									
								
							|  | @ -1,5 +1,6 @@ | ||||||
| //! Machine-level Intermediate Representation
 | //! Machine-level Intermediate Representation
 | ||||||
| 
 | 
 | ||||||
|  | use std::collections::btree_map::Entry; | ||||||
| use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque}; | use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque}; | ||||||
| 
 | 
 | ||||||
| use itertools::Itertools; | use itertools::Itertools; | ||||||
|  | @ -108,6 +109,8 @@ pub enum Inst { | ||||||
|     ConstantDWord, |     ConstantDWord, | ||||||
|     /// imm64
 |     /// imm64
 | ||||||
|     ConstantQWord, |     ConstantQWord, | ||||||
|  |     /// src
 | ||||||
|  |     LoadConstant(Type), // hint for loading constant into register
 | ||||||
|     /// ast-node
 |     /// ast-node
 | ||||||
|     ExternRef, |     ExternRef, | ||||||
|     /// size, align
 |     /// size, align
 | ||||||
|  | @ -156,6 +159,40 @@ pub enum Inst { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Inst { | impl Inst { | ||||||
|  |     fn value_type(&self) -> Option<Type> { | ||||||
|  |         match self { | ||||||
|  |             Inst::Label | ||||||
|  |             | Inst::ConstantBytes | ||||||
|  |             | Inst::ConstantByte | ||||||
|  |             | Inst::ConstantWord | ||||||
|  |             | Inst::ConstantDWord | ||||||
|  |             | Inst::ConstantQWord | ||||||
|  |             | Inst::ExternRef | ||||||
|  |             | Inst::Alloca | ||||||
|  |             | Inst::ReturnValue | ||||||
|  |             | Inst::Store(_) | ||||||
|  |             | Inst::Return => None, | ||||||
|  |             Inst::GetElementPtr(ty) | ||||||
|  |             | Inst::Load(ty) | ||||||
|  |             | Inst::LoadConstant(ty) | ||||||
|  |             | Inst::Parameter(ty) | ||||||
|  |             | Inst::Add(ty) | ||||||
|  |             | Inst::Sub(ty) | ||||||
|  |             | Inst::Mul(ty) | ||||||
|  |             | Inst::MulSigned(ty) | ||||||
|  |             | Inst::Div(ty) | ||||||
|  |             | Inst::DivSigned(ty) | ||||||
|  |             | Inst::Rem(ty) | ||||||
|  |             | Inst::RemSigned(ty) | ||||||
|  |             | Inst::BitAnd(ty) | ||||||
|  |             | Inst::BitOr(ty) | ||||||
|  |             | Inst::BitXOr(ty) | ||||||
|  |             | Inst::Negate(ty) | ||||||
|  |             | Inst::ShiftLeft(ty) | ||||||
|  |             | Inst::ShiftRightSigned(ty) | ||||||
|  |             | Inst::ShiftRightUnsigned(ty) => Some(*ty), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|     fn has_value(&self) -> bool { |     fn has_value(&self) -> bool { | ||||||
|         // basically, when an arithmetic instruction has two immediates, then just replace it with a mov into the dst reg
 |         // basically, when an arithmetic instruction has two immediates, then just replace it with a mov into the dst reg
 | ||||||
|         match self { |         match self { | ||||||
|  | @ -172,6 +209,7 @@ impl Inst { | ||||||
|             | Inst::Return => false, |             | Inst::Return => false, | ||||||
|             Inst::GetElementPtr(_) |             Inst::GetElementPtr(_) | ||||||
|             | Inst::Load(_) |             | Inst::Load(_) | ||||||
|  |             | Inst::LoadConstant(_) | ||||||
|             | Inst::Parameter(_) |             | Inst::Parameter(_) | ||||||
|             | Inst::Add(_) |             | Inst::Add(_) | ||||||
|             | Inst::Sub(_) |             | Inst::Sub(_) | ||||||
|  | @ -307,6 +345,9 @@ impl Mir { | ||||||
|     pub fn gen_u64(&mut self, value: u64) -> u32 { |     pub fn gen_u64(&mut self, value: u64) -> u32 { | ||||||
|         self.push(Inst::ConstantQWord, Data::imm64(value)) |         self.push(Inst::ConstantQWord, Data::imm64(value)) | ||||||
|     } |     } | ||||||
|  |     pub fn gen_load_const(&mut self, ty: Type, src: u32) -> u32 { | ||||||
|  |         self.push(Inst::LoadConstant(ty), Data::node(src)) | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     pub fn gen_label(&mut self, name: StringsIndex) -> u32 { |     pub fn gen_label(&mut self, name: StringsIndex) -> u32 { | ||||||
|         self.push(Inst::Label, Data::index(name)) |         self.push(Inst::Label, Data::index(name)) | ||||||
|  | @ -439,7 +480,7 @@ impl Mir { | ||||||
|         &self, |         &self, | ||||||
|         w: &mut W, |         w: &mut W, | ||||||
|         strings: &StringTable, |         strings: &StringTable, | ||||||
|         reg_alloc: &HashMap<u32, amd64::Register>, |         reg_alloc: &BTreeMap<u32, amd64::Register>, | ||||||
|         node: u32, |         node: u32, | ||||||
|     ) -> core::fmt::Result { |     ) -> core::fmt::Result { | ||||||
|         let idx = node as usize; |         let idx = node as usize; | ||||||
|  | @ -461,6 +502,10 @@ impl Mir { | ||||||
|             Inst::ConstantWord => writeln!(w, "%{node} = imm16({:x?})", data.as_imm16()), |             Inst::ConstantWord => writeln!(w, "%{node} = imm16({:x?})", data.as_imm16()), | ||||||
|             Inst::ConstantDWord => writeln!(w, "%{node} = imm32({:x?})", data.as_imm32()), |             Inst::ConstantDWord => writeln!(w, "%{node} = imm32({:x?})", data.as_imm32()), | ||||||
|             Inst::ConstantQWord => writeln!(w, "%{node} = imm64({:x?})", data.as_imm64()), |             Inst::ConstantQWord => writeln!(w, "%{node} = imm64({:x?})", data.as_imm64()), | ||||||
|  |             Inst::LoadConstant(ty) => { | ||||||
|  |                 let src = data.as_node(); | ||||||
|  |                 writeln!(w, "%{node} = load constant {ty} %{src}") | ||||||
|  |             } | ||||||
|             Inst::ExternRef => writeln!(w, "%{node} = extern %%{}", data.as_node()), |             Inst::ExternRef => writeln!(w, "%{node} = extern %%{}", data.as_node()), | ||||||
|             Inst::Alloca => { |             Inst::Alloca => { | ||||||
|                 let (size, align) = data.as_binary(); |                 let (size, align) = data.as_binary(); | ||||||
|  | @ -568,19 +613,18 @@ impl Mir { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Mir { | impl Mir { | ||||||
|     pub fn build_liveness(&self) -> HashMap<u32, amd64::Register> { |     pub fn build_liveness(&self) -> BTreeMap<u32, amd64::Register> { | ||||||
|         struct Interval { |         struct Interval { | ||||||
|             start: u32, |             start: u32, | ||||||
|             end: u32, |             end: u32, | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let mut references = BTreeMap::<u32, Vec<u32>>::new(); |         let mut references = BTreeMap::<u32, Vec<u32>>::new(); | ||||||
|         let mut prefered_colors = BTreeMap::<u32, amd64::Register>::new(); |         let mut preferred_colors = BTreeMap::<u32, amd64::Register>::new(); | ||||||
|         use amd64::Register::*; |         use amd64::Register::*; | ||||||
|         let mut param_registers = [rsi, rdi, rdx, rcx, r8, r9] |         let mut in_colors = [r9, r8, rcx, rdx, rdi, rsi].to_vec(); | ||||||
|             .into_iter() |         let mut in_colors_sse = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0].to_vec(); | ||||||
|             .rev() |         let mut inouts = Vec::<u32>::new(); | ||||||
|             .collect::<Vec<_>>(); |  | ||||||
| 
 | 
 | ||||||
|         for i in 0..self.nodes.len() { |         for i in 0..self.nodes.len() { | ||||||
|             let inst = self.nodes[i]; |             let inst = self.nodes[i]; | ||||||
|  | @ -590,20 +634,26 @@ impl Mir { | ||||||
|             references.insert(node, Vec::new()); |             references.insert(node, Vec::new()); | ||||||
| 
 | 
 | ||||||
|             match inst { |             match inst { | ||||||
|                 Inst::Parameter(_) => { |                 Inst::Parameter(ty) => { | ||||||
|                     if let Some(reg) = param_registers.pop() { |                     if let Some(reg) = if ty.is_floating() { | ||||||
|  |                         in_colors_sse.pop() | ||||||
|  |                     } else { | ||||||
|  |                         in_colors.pop() | ||||||
|  |                     } { | ||||||
|                         println!("prefering {reg} for param"); |                         println!("prefering {reg} for param"); | ||||||
|                         prefered_colors.insert(node, reg); |                         preferred_colors.insert(node, reg); | ||||||
|                     } |                     }; | ||||||
|                 } |                     inouts.push(node); | ||||||
|                 Inst::Negate(_) | Inst::Load(_) => { |  | ||||||
|                     references.get_mut(&data.as_node()).unwrap().push(node); |  | ||||||
|                 } |                 } | ||||||
|                 // return is thru rax.
 |                 // return is thru rax.
 | ||||||
|                 Inst::ReturnValue => { |                 Inst::ReturnValue => { | ||||||
|                     let val = data.as_node(); |                     let val = data.as_node(); | ||||||
|  |                     inouts.push(val); | ||||||
|                     references.get_mut(&val).unwrap().push(node); |                     references.get_mut(&val).unwrap().push(node); | ||||||
|                     _ = prefered_colors.try_insert(val, amd64::Register::rax); |                     _ = preferred_colors.try_insert(val, amd64::Register::rax); | ||||||
|  |                 } | ||||||
|  |                 Inst::Negate(_) | Inst::Load(_) => { | ||||||
|  |                     references.get_mut(&data.as_node()).unwrap().push(node); | ||||||
|                 } |                 } | ||||||
|                 Inst::GetElementPtr(_) => { |                 Inst::GetElementPtr(_) => { | ||||||
|                     let (src, _) = data.as_binary(); |                     let (src, _) = data.as_binary(); | ||||||
|  | @ -617,24 +667,38 @@ impl Mir { | ||||||
|                     references.get_mut(&rhs).unwrap().push(node); |                     references.get_mut(&rhs).unwrap().push(node); | ||||||
| 
 | 
 | ||||||
|                     if !ty.is_floating() { |                     if !ty.is_floating() { | ||||||
|                         _ = prefered_colors.try_insert(lhs, amd64::Register::rax); |                         _ = preferred_colors.try_insert(lhs, amd64::Register::rax); | ||||||
|                         _ = prefered_colors.try_insert(rhs, amd64::Register::rax); |                         _ = preferred_colors.try_insert(rhs, amd64::Register::rax); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 // mul wants lhs to be rax, imul can do either.
 |                 // div wants lhs to be rax, idiv can do either.
 | ||||||
|                 // note that it also clobers rdx
 |                 // note that it also clobers rdx
 | ||||||
|                 Inst::Div(_) | Inst::DivSigned(_) | Inst::Rem(_) | Inst::RemSigned(_) => { |                 Inst::Div(ty) | Inst::DivSigned(ty) => { | ||||||
|                     let (lhs, rhs) = data.as_binary(); |                     let (lhs, rhs) = data.as_binary(); | ||||||
|                     references.get_mut(&lhs).unwrap().push(node); |                     references.get_mut(&lhs).unwrap().push(node); | ||||||
|                     references.get_mut(&rhs).unwrap().push(node); |                     references.get_mut(&rhs).unwrap().push(node); | ||||||
|                     _ = prefered_colors.try_insert(lhs, amd64::Register::rax); | 
 | ||||||
|  |                     if !ty.is_floating() { | ||||||
|  |                         _ = preferred_colors.try_insert(lhs, amd64::Register::rax); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 // div wants lhs to be rax, idiv can do either.
 | ||||||
|  |                 // note that it also clobers rax
 | ||||||
|  |                 Inst::Rem(ty) | Inst::RemSigned(ty) => { | ||||||
|  |                     let (lhs, rhs) = data.as_binary(); | ||||||
|  |                     references.get_mut(&lhs).unwrap().push(node); | ||||||
|  |                     references.get_mut(&rhs).unwrap().push(node); | ||||||
|  | 
 | ||||||
|  |                     if !ty.is_floating() { | ||||||
|  |                         _ = preferred_colors.try_insert(lhs, amd64::Register::rdx); | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|                 // shr,shl,sar want the shift to be in cl.
 |                 // shr,shl,sar want the shift to be in cl.
 | ||||||
|                 Inst::ShiftLeft(_) | Inst::ShiftRightSigned(_) | Inst::ShiftRightUnsigned(_) => { |                 Inst::ShiftLeft(_) | Inst::ShiftRightSigned(_) | Inst::ShiftRightUnsigned(_) => { | ||||||
|                     let (lhs, rhs) = data.as_binary(); |                     let (lhs, rhs) = data.as_binary(); | ||||||
|                     references.get_mut(&lhs).unwrap().push(node); |                     references.get_mut(&lhs).unwrap().push(node); | ||||||
|                     references.get_mut(&rhs).unwrap().push(node); |                     references.get_mut(&rhs).unwrap().push(node); | ||||||
|                     _ = prefered_colors.try_insert(rhs, amd64::Register::rcx); |                     _ = preferred_colors.try_insert(rhs, amd64::Register::rcx); | ||||||
|                 } |                 } | ||||||
|                 // add,adc,sub,sbb,or,and,xor and mov don't care much about their source registers
 |                 // add,adc,sub,sbb,or,and,xor and mov don't care much about their source registers
 | ||||||
|                 Inst::Add(_) |                 Inst::Add(_) | ||||||
|  | @ -652,7 +716,7 @@ impl Mir { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         references.retain(|&node, refs| !refs.is_empty() && self.nodes[node as usize].has_value()); |         references.retain(|&node, refs| !refs.is_empty() && self.nodes[node as usize].has_value()); | ||||||
|         prefered_colors.retain(|&node, _| self.nodes[node as usize].has_value()); |         preferred_colors.retain(|&node, _| self.nodes[node as usize].has_value()); | ||||||
| 
 | 
 | ||||||
|         let intervals = references |         let intervals = references | ||||||
|             .iter() |             .iter() | ||||||
|  | @ -675,40 +739,153 @@ impl Mir { | ||||||
|         } |         } | ||||||
|         let inference_graph = petgraph::graph::UnGraph::<(), ()>::from_edges(edges.into_iter()); |         let inference_graph = petgraph::graph::UnGraph::<(), ()>::from_edges(edges.into_iter()); | ||||||
| 
 | 
 | ||||||
|         let gprs = amd64::Register::gp_registers(); |         #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] | ||||||
|         let sses = amd64::Register::sse_registers(); |         enum Color { | ||||||
|  |             #[default] | ||||||
|  |             Unassigned, | ||||||
|  |             Tentative(amd64::Register), | ||||||
|  |             Final(amd64::Register), | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         let mut assigned_colors = HashMap::<u32, amd64::Register>::new(); |         impl Color { | ||||||
|         for &node in references.keys().rev() { |             fn color(self) -> Option<amd64::Register> { | ||||||
|             if matches!(self.nodes[node as usize], Inst::Alloca) { |                 match self { | ||||||
|                 continue; |                     Color::Unassigned => None, | ||||||
|  |                     Color::Tentative(color) | Color::Final(color) => Some(color), | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         struct Colorizer<'a> { | ||||||
|  |             mir: &'a Mir, | ||||||
|  |             graph: petgraph::graph::UnGraph<(), ()>, | ||||||
|  |             colors: BTreeMap<u32, Color>, | ||||||
|  |             preferred: BTreeMap<u32, amd64::Register>, | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         impl<'a> Colorizer<'a> { | ||||||
|  |             fn node_colors(&self, node: petgraph::graph::NodeIndex) -> &[amd64::Register] { | ||||||
|  |                 let colors = if self.mir.nodes[node.index()] | ||||||
|  |                     .value_type() | ||||||
|  |                     .map(|t| t.is_floating()) | ||||||
|  |                     == Some(true) | ||||||
|  |                 { | ||||||
|  |                     &amd64::Register::SSE[..] | ||||||
|  |                 } else { | ||||||
|  |                     &amd64::Register::GPR[..] | ||||||
|  |                 }; | ||||||
|  |                 colors | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             let clique_colors = inference_graph |             fn prepass<I: IntoIterator<Item = u32>>(&mut self, inouts: I) { | ||||||
|                 .neighbors(node.into()) |                 for node in inouts.into_iter() { | ||||||
|                 .filter_map(|e| assigned_colors.get(&(e.index() as u32)).cloned()) |                     self.precolor_node(node.into()); | ||||||
|                 .collect::<BTreeSet<_>>(); |                 } | ||||||
|             let clique_preferred_colors = inference_graph |  | ||||||
|                 .neighbors(node.into()) |  | ||||||
|                 .filter_map(|e| prefered_colors.get(&(e.index() as u32)).cloned()) |  | ||||||
|                 .collect::<BTreeSet<_>>(); |  | ||||||
| 
 | 
 | ||||||
|             let color = prefered_colors |                 let keys = self.preferred.keys().cloned().collect::<Vec<_>>(); | ||||||
|                 .get(&node) |                 for node in keys { | ||||||
|                 .into_iter() |                     self.precolor_node(node.into()); | ||||||
|                 .chain(gprs.iter()) |                 } | ||||||
|                 .filter(|reg| !clique_colors.contains(reg)) |             } | ||||||
|                 .find_or_first(|®| !clique_preferred_colors.contains(reg)) |  | ||||||
|                 .cloned() |  | ||||||
|                 .expect("ran out of registers"); |  | ||||||
| 
 | 
 | ||||||
|             println!("%{node} wants {:?}\n\tclique: {clique_colors:?}\n\tclique prefs: {clique_preferred_colors:?}\n\t-> {color}", prefered_colors.get(&node)); |             fn precolor_node(&mut self, node: petgraph::graph::NodeIndex) { | ||||||
|  |                 // 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; | ||||||
|  |                 // only apply color here if we have a preference
 | ||||||
|  |                 if let Some(preferred_color) = self.preferred.remove(&node_u32) { | ||||||
|  |                     let mut clique_colors = self | ||||||
|  |                         .graph | ||||||
|  |                         .neighbors(node) | ||||||
|  |                         .filter_map(|n| self.colors.get(&(n.index() as u32)).cloned()); | ||||||
| 
 | 
 | ||||||
|             prefered_colors.remove(&node); |                     if clique_colors | ||||||
|  |                         .find(|color| color.color() == Some(preferred_color)) | ||||||
|  |                         .is_none() | ||||||
|  |                     { | ||||||
|  |                         self.colors | ||||||
|  |                             .insert(node_u32, Color::Tentative(preferred_color)); | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|  |                 // .chain(self.node_colors(node).into_iter().cloned());
 | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|             assigned_colors.insert(node, color); |             fn color_node(&mut self, node: petgraph::graph::NodeIndex) { | ||||||
|  |                 // final pass:
 | ||||||
|  |                 // look at clique colors and prefer to steal colors from
 | ||||||
|  |                 // tentatively colored nodes. this results in preferential
 | ||||||
|  |                 // coloring depending on the order of the prepass.
 | ||||||
|  |                 let node_u32 = node.index() as u32; | ||||||
|  |                 let clique_colors = self | ||||||
|  |                     .graph | ||||||
|  |                     .neighbors(node) | ||||||
|  |                     .filter_map(|n| self.colors.get(&(n.index() as u32)).cloned()) | ||||||
|  |                     .collect::<BTreeSet<_>>(); | ||||||
|  | 
 | ||||||
|  |                 let colors = self | ||||||
|  |                     .node_colors(node) | ||||||
|  |                     .into_iter() | ||||||
|  |                     .filter(|&&r| !clique_colors.contains(&Color::Final(r))) | ||||||
|  |                     .cloned() | ||||||
|  |                     .collect::<BTreeSet<_>>(); | ||||||
|  | 
 | ||||||
|  |                 // eprintln!("coloring %{node_u32}:");
 | ||||||
|  |                 // eprintln!("\twants: {:?}", self.colors.get(&node_u32));
 | ||||||
|  |                 // eprintln!("\tclique: {clique_colors:?}");
 | ||||||
|  |                 // eprintln!("\tcandidates: {colors:?}");
 | ||||||
|  | 
 | ||||||
|  |                 match self.colors.entry(node_u32) { | ||||||
|  |                     Entry::Vacant(v) => { | ||||||
|  |                         // here we want to first check clique_colors with tentative coloring.
 | ||||||
|  |                         let color = colors | ||||||
|  |                             .into_iter() | ||||||
|  |                             .find_or_first(|&c| !clique_colors.contains(&Color::Tentative(c))) | ||||||
|  |                             .expect("ran out of registers :("); | ||||||
|  |                         v.insert(Color::Final(color)); | ||||||
|  |                     } | ||||||
|  |                     Entry::Occupied(mut e) => { | ||||||
|  |                         // we prefer to steal
 | ||||||
|  |                         variant!(e.get() => &Color::Tentative(reg)); | ||||||
|  |                         let color = colors | ||||||
|  |                             .into_iter() | ||||||
|  |                             .find_or_first(|&c| c == reg) | ||||||
|  |                             .expect("ran out of registers :("); | ||||||
|  |                         e.insert(Color::Final(color)); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             fn finalise(self) -> BTreeMap<u32, amd64::Register> { | ||||||
|  |                 self.colors | ||||||
|  |                     .into_iter() | ||||||
|  |                     .filter_map(|(node, c)| match c { | ||||||
|  |                         Color::Final(reg) => Some((node, reg)), | ||||||
|  |                         _ => None, | ||||||
|  |                     }) | ||||||
|  |                     .collect() | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         let mut colorizer = Colorizer { | ||||||
|  |             mir: self, | ||||||
|  |             graph: inference_graph, | ||||||
|  |             preferred: preferred_colors, | ||||||
|  |             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(inouts); | ||||||
|  | 
 | ||||||
|  |         for &node in references.keys().rev() { | ||||||
|  |             if !self.nodes[node as usize].has_value() { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             colorizer.color_node(node.into()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let colors = colorizer.finalise(); | ||||||
|  | 
 | ||||||
|         // eprintln!(
 |         // eprintln!(
 | ||||||
|         //     "Inference Graph:\n{:?}",
 |         //     "Inference Graph:\n{:?}",
 | ||||||
|         //     petgraph::dot::Dot::with_attr_getters(
 |         //     petgraph::dot::Dot::with_attr_getters(
 | ||||||
|  | @ -729,9 +906,10 @@ impl Mir { | ||||||
|         //     ),
 |         //     ),
 | ||||||
|         // );
 |         // );
 | ||||||
| 
 | 
 | ||||||
|         assigned_colors |         colors | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
| pub struct DisplayMir<'a, 'b> { | pub struct DisplayMir<'a, 'b> { | ||||||
|     mir: &'a Mir, |     mir: &'a Mir, | ||||||
|     strings: &'b StringTable, |     strings: &'b StringTable, | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue