global symbols

This commit is contained in:
Janis 2024-09-02 12:59:17 +02:00
parent 4b432f404b
commit 4424ef875d
4 changed files with 336 additions and 315 deletions

View file

@ -77,13 +77,28 @@ fn main() {
mir.build(); mir.build();
let MirBuilder { let MirBuilder {
strings, functions, .. globals,
strings,
functions,
..
} = mir; } = mir;
println!(".intel_syntax"); println!(".intel_syntax");
println!(".text"); println!(".text");
for (_name, mir) in globals {
let assembly = mir
.assemble(&strings)
.unwrap()
.finish_constants(&strings)
.unwrap();
println!("{assembly}");
}
for (_name, mir) in functions { for (_name, mir) in functions {
let assembly = mir.assemble(&strings).unwrap(); let assembly = mir
.assemble(&strings)
.unwrap()
.finish_as_function(&strings)
.unwrap();
println!("{assembly}"); println!("{assembly}");
} }
} }

View file

@ -2,14 +2,13 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::btree_map::Entry; use std::collections::btree_map::Entry;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::collections::{BTreeMap, BTreeSet};
use std::fmt::Display; use std::fmt::Display;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::iter::FusedIterator; use std::iter::FusedIterator;
use std::u32; use std::u32;
use itertools::Itertools; use itertools::Itertools;
use liveness::LivenessBuilder;
use crate::asm::amd64::Register; use crate::asm::amd64::Register;
use crate::ast::IntegralType; use crate::ast::IntegralType;
@ -138,8 +137,8 @@ pub enum Inst {
ConstantDoublePrecision, ConstantDoublePrecision,
/// src /// src
LoadRegister(Type), // hint for loading value into register LoadRegister(Type), // hint for loading value into register
/// ast-node /// index
ExternRef, ExternRef(Option<Type>), // might have a type, or might be a name only,
/// size, align /// size, align
Alloca, Alloca,
/// src /// src
@ -224,9 +223,9 @@ pub enum Inst {
impl Inst { impl Inst {
fn value_type(&self) -> Option<Type> { fn value_type(&self) -> Option<Type> {
match self { match self {
Inst::ExternRef(ty) => *ty,
Inst::Label Inst::Label
| Inst::ConstantBytes | Inst::ConstantBytes
| Inst::ExternRef
| Inst::Alloca | Inst::Alloca
| Inst::ReturnValue(_) | Inst::ReturnValue(_)
| Inst::Store(_) | Inst::Store(_)
@ -290,7 +289,7 @@ impl Inst {
| Inst::ConstantQWord | Inst::ConstantQWord
| Inst::ConstantSinglePrecision | Inst::ConstantSinglePrecision
| Inst::ConstantDoublePrecision | Inst::ConstantDoublePrecision
| Inst::ExternRef | Inst::ExternRef(_)
| Inst::Alloca | Inst::Alloca
| Inst::Store(_) | Inst::Store(_)
| Inst::ReturnValue(_) | Inst::ReturnValue(_)
@ -950,6 +949,9 @@ impl Mir {
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))
} }
pub fn gen_extern(&mut self, ty: Option<Type>, name: StringsIndex) -> u32 {
self.push(Inst::ExternRef(ty), Data::index(name))
}
pub fn gen_alloca(&mut self, size: u32, align: u32) -> u32 { pub fn gen_alloca(&mut self, size: u32, align: u32) -> u32 {
self.push(Inst::Alloca, Data::binary(size, align)) self.push(Inst::Alloca, Data::binary(size, align))
} }
@ -1190,7 +1192,13 @@ impl Mir {
let src = data.as_node(); let src = data.as_node();
writeln!(w, "%{node} = load register {ty} %{src}") writeln!(w, "%{node} = load register {ty} %{src}")
} }
Inst::ExternRef => writeln!(w, "%{node} = extern %%{}", data.as_node()), Inst::ExternRef(ty) => {
write!(w, "%{node} = extern ")?;
if let Some(ty) = ty {
write!(w, "{ty} ")?;
}
writeln!(w, "{}", strings.get_str(data.as_index()))
}
Inst::Alloca => { Inst::Alloca => {
let (size, align) = data.as_binary(); let (size, align) = data.as_binary();
writeln!(w, "%{node} = alloca {size}, {align}") writeln!(w, "%{node} = alloca {size}, {align}")
@ -1497,9 +1505,6 @@ pub mod liveness {
let branch_graph = BranchGraph::from_edges(branch_graph_edges); let branch_graph = BranchGraph::from_edges(branch_graph_edges);
eprintln!("branch graph: {branch_graph:?}");
eprintln!("references: {references:?}");
let mut intervals = mir let mut intervals = mir
.indices() .indices()
.filter_map(|node| { .filter_map(|node| {
@ -1530,9 +1535,6 @@ pub mod liveness {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
eprintln!("intervals: {intervals:#?}");
eprintln!("edges: {edges:#?}");
// build interference graph with mutliple branches. // build interference graph with mutliple branches.
// BTreeMap<MirRange, Interferencegraph> // BTreeMap<MirRange, Interferencegraph>
type Edge = (NodeRef, NodeRef); type Edge = (NodeRef, NodeRef);
@ -1562,8 +1564,6 @@ pub mod liveness {
} }
} }
eprintln!("per_branch_edges: {per_branch_edges:?}");
let branches = per_branch_edges let branches = per_branch_edges
.into_iter() .into_iter()
.map(|(range, edges)| { .map(|(range, edges)| {
@ -1573,7 +1573,6 @@ pub mod liveness {
) )
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
eprintln!("branches: {branches:#?}");
Self { Self {
branches, branches,
@ -1651,12 +1650,6 @@ pub mod liveness {
} }
} }
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
struct LivenessReference {
node: NodeRef,
referenced_by: NodeRef,
}
pub struct BranchedLivenessBuilder<'a> { pub struct BranchedLivenessBuilder<'a> {
mir: &'a Mir, mir: &'a Mir,
// tree of (node, referenced_by) pairs. // tree of (node, referenced_by) pairs.
@ -1785,21 +1778,6 @@ pub mod liveness {
} }
} }
pub struct LivenessBuilder<'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)>,
inference_graph: petgraph::graph::UnGraph<(), ()>,
// list of preferred colors by nodes, either because they output to some
// register like mul/div or because the write to one of their inputs.
// interesting to consider optimisations like i >>= s being turned into shl
// mem, cl, while i >> s is turned into shl reg, cl ...
// preferred_color: BTreeMap<NodeRef, Register>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
enum Color { enum Color {
Tentative(Register), Tentative(Register),
@ -1814,103 +1792,6 @@ pub mod liveness {
} }
} }
impl<'a> LivenessBuilder<'a> {
pub fn new(mir: &'a Mir) -> Self {
let references = build_reference_tree(mir);
let intervals = mir.indices().filter_map(|node| {
let interval = references
.range(node.into_reference_range())
.map(|&(_, to)| to)
.reduce(|acc, to| acc.max(to));
interval.map(|max| (node, max))
});
let mut edges = HashSet::<(u32, u32)>::new();
// eprint!("intervals: [");
for (from, to) in intervals {
// eprint!("({from})..({to}), ");
if !mir.is_register(from.0) {
continue;
}
for &(other, _) in references.range(from.exclusive_start()..to.exclusive_end()) {
edges.insert((from.0, other.0));
}
}
// eprintln!("]");
let inference_graph = petgraph::graph::UnGraph::<(), ()>::from_edges(edges.into_iter());
Self {
mir,
inference_graph,
// references,
}
}
fn pre_color_colors(&self) -> BTreeMap<NodeRef, Register> {
/* 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::<NodeRef, Register>::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
.inference_graph
.find_edge(dst.0.into(), node.0.into())
.is_none()
{
// 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
}
}
fn build_reference_tree(mir: &Mir) -> BTreeSet<(NodeRef, NodeRef)> { fn build_reference_tree(mir: &Mir) -> BTreeSet<(NodeRef, NodeRef)> {
let mut references = BTreeSet::new(); let mut references = BTreeSet::new();
for node in mir.indices() { for node in mir.indices() {
@ -2008,10 +1889,10 @@ pub mod liveness {
.cloned() .cloned()
.collect::<BTreeSet<_>>(); .collect::<BTreeSet<_>>();
eprintln!("coloring %{node_u32}:"); // eprintln!("coloring %{node_u32}:");
eprintln!("\twants: {:?}", self.colors.get(&node_ref)); // eprintln!("\twants: {:?}", self.colors.get(&node_ref));
eprintln!("\tclique: {clique_colors:?}"); // eprintln!("\tclique: {clique_colors:?}");
eprintln!("\tcandidates: {colors:?}"); // eprintln!("\tcandidates: {colors:?}");
let color = match self.colors.entry(node_ref) { let color = match self.colors.entry(node_ref) {
Entry::Vacant(v) => { Entry::Vacant(v) => {
@ -2044,7 +1925,6 @@ pub mod liveness {
// for any Phi(y_1,y_2, y_n) give y_i the color of Phi // 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. // reasonably certain that this will never fail to color all phi nodes the same color.
if let Some(inputs) = self.mir.get_phi_inputs(node_ref) { if let Some(inputs) = self.mir.get_phi_inputs(node_ref) {
eprintln!("coloring {inputs:?} {color}");
for node in inputs { for node in inputs {
_ = self.colors.insert(node, Color::Tentative(color)); _ = self.colors.insert(node, Color::Tentative(color));
} }
@ -2139,7 +2019,7 @@ impl Mir {
| Inst::ConstantQWord | Inst::ConstantQWord
| Inst::ConstantSinglePrecision | Inst::ConstantSinglePrecision
| Inst::ConstantDoublePrecision | Inst::ConstantDoublePrecision
| Inst::ExternRef | Inst::ExternRef(_)
| Inst::Alloca => {} | Inst::Alloca => {}
} }
} }
@ -2191,7 +2071,7 @@ impl Mir {
| Inst::ConstantQWord | Inst::ConstantQWord
| Inst::ConstantSinglePrecision | Inst::ConstantSinglePrecision
| Inst::ConstantDoublePrecision | Inst::ConstantDoublePrecision
| Inst::ExternRef | Inst::ExternRef(_)
| Inst::Alloca | Inst::Alloca
| Inst::Jump | Inst::Jump
| Inst::Return | Inst::Return
@ -2359,6 +2239,27 @@ impl Function {
} }
} }
pub fn finish_as_function(self, strings: &StringTable) -> Result<String, core::fmt::Error> {
let mut buf = String::new();
self.finish(&mut buf, strings)?;
Ok(buf)
}
pub fn finish_constants(self, strings: &StringTable) -> Result<String, core::fmt::Error> {
use core::fmt::Write;
let mut buf = String::new();
let w = &mut buf;
let name = strings.get_str(self.name).to_owned();
writeln!(w, ".{name}:")?;
for (_, contents) in self.constants {
writeln!(w, "{contents}")?;
}
Ok(buf)
}
#[allow(dead_code)] #[allow(dead_code)]
fn dirty_register(&mut self, reg: Register) { fn dirty_register(&mut self, reg: Register) {
self.dirty_registers.insert(reg); self.dirty_registers.insert(reg);
@ -2436,10 +2337,15 @@ impl Function {
writeln!(w, "push {reg}")?; writeln!(w, "push {reg}")?;
} }
writeln!(w, "push rbp")?; let needs_frame = !saved_registers.is_empty() && self.stack_offset != 0;
writeln!(w, "mov rbp, rsp")?;
writeln!(w, "sub rsp, {}", self.stack_offset)?;
if needs_frame {
writeln!(w, "push rbp")?;
writeln!(w, "mov rbp, rsp")?;
writeln!(w, "sub rsp, {}", self.stack_offset)?;
}
// zero rax because we might only return into some of it
writeln!(w, "test rax, rax")?;
write!(w, "{}", self.branches.remove(&NodeRef::MIN).unwrap())?; write!(w, "{}", self.branches.remove(&NodeRef::MIN).unwrap())?;
for (branch, content) in &self.branches { for (branch, content) in &self.branches {
@ -2448,12 +2354,16 @@ impl Function {
} }
writeln!(w, ".{name}__epilogue:")?; writeln!(w, ".{name}__epilogue:")?;
writeln!(w, "mov rsp, rbp")?;
writeln!(w, "pop rbp")?;
for reg in saved_registers.iter().rev() { if needs_frame {
writeln!(w, "pop {reg}")?; writeln!(w, "mov rsp, rbp")?;
writeln!(w, "pop rbp")?;
for reg in saved_registers.iter().rev() {
writeln!(w, "pop {reg}")?;
}
} }
writeln!(w, "ret")?; writeln!(w, "ret")?;
Ok(()) Ok(())
@ -2542,14 +2452,20 @@ impl Mir {
let (offset, size) = *mapping.get(&(node as usize)).unwrap(); let (offset, size) = *mapping.get(&(node as usize)).unwrap();
ImmRegMem::Mem(StackMem::new(offset, size)) ImmRegMem::Mem(StackMem::new(offset, size))
} }
Inst::ExternRef => todo!(), Inst::ExternRef(ty) => {
let ty = ty.unwrap_or(Type::QWord);
ImmRegMem::Rip(RipRelative::Label(
ty,
format!(".{}", strings.get_str(data.as_index())),
))
}
_ => { _ => {
unreachable!() unreachable!()
} }
} }
} }
pub fn assemble(&self, strings: &StringTable) -> Result<String, core::fmt::Error> { pub fn assemble(&self, strings: &StringTable) -> Result<Function, core::fmt::Error> {
use core::fmt::Write; use core::fmt::Write;
// mapping if (i, (stack_offset, bytes)) for local stack variables // mapping if (i, (stack_offset, bytes)) for local stack variables
let mut mapping = BTreeMap::<usize, (u32, u32)>::new(); let mut mapping = BTreeMap::<usize, (u32, u32)>::new();
@ -2574,7 +2490,9 @@ impl Mir {
| Inst::ConstantByte | Inst::ConstantByte
| Inst::ConstantWord | Inst::ConstantWord
| Inst::ConstantDWord | Inst::ConstantDWord
| Inst::ConstantQWord => {} | Inst::ConstantQWord => {
func.add_constant_from_inst_and_data(i, inst, data, strings);
}
Inst::ConstantSinglePrecision => { Inst::ConstantSinglePrecision => {
let bits = data.as_imm32(); let bits = data.as_imm32();
func.add_constant(i, format!(".long {bits}")); func.add_constant(i, format!(".long {bits}"));
@ -2631,7 +2549,7 @@ impl Mir {
writeln!(func.current_branch(), "mov {dst}, {src}",)?; writeln!(func.current_branch(), "mov {dst}, {src}",)?;
} }
} }
Inst::ExternRef => todo!(), Inst::ExternRef(_) => {}
Inst::Alloca => { Inst::Alloca => {
let (size, align) = data.as_binary(); let (size, align) = data.as_binary();
let offset = func.alloca(size, align); let offset = func.alloca(size, align);
@ -3553,10 +3471,7 @@ impl Mir {
} }
} }
let mut buf = String::new(); Ok(func)
func.finish(&mut buf, strings)?;
Ok(buf)
} }
} }

View file

@ -374,24 +374,19 @@ impl Tree {
}; };
let name_str = self.strings.get_str(self.ident_index(name)).to_owned(); let name_str = self.strings.get_str(self.ident_index(name)).to_owned();
let node = { let decl = self.nodes.reserve_node();
let node = self.nodes.reserve_node();
self.st.insert_symbol(&name_str, node, SymbolKind::Var);
node
};
let assignment = if tokens.eat_token(Token::Equal).is_some() { let assignment = if tokens.eat_token(Token::Equal).is_some() {
let expr = self.parse_expr(tokens)?; Some(self.parse_expr(tokens)?)
Some(self.nodes.push_tag(Tag::Assign {
lhs: node,
rhs: expr,
}))
} else { } else {
None None
}; };
// insert into symbol table after parsing assignment in case we are shadowing a previous variable binding
self.st.insert_symbol(&name_str, decl, SymbolKind::Var);
self.nodes.set_node( self.nodes.set_node(
node, decl,
Tag::VarDecl { Tag::VarDecl {
let_or_var, let_or_var,
name, name,
@ -401,7 +396,7 @@ impl Tree {
); );
// return assignment if it exists, to make rendering and visiting easier // return assignment if it exists, to make rendering and visiting easier
Ok(assignment.unwrap_or(node)) Ok(decl)
} }
/// GLOBAL_DECL <- /// GLOBAL_DECL <-
@ -418,7 +413,9 @@ impl Tree {
}; };
let name_str = self.get_ident_str(name).unwrap().to_owned(); let name_str = self.get_ident_str(name).unwrap().to_owned();
let node = {
// inserting root symbol here is fine, because self-referencing globals are stupid
let decl = {
let node = match self.st.find_root_symbol(&name_str) { let node = match self.st.find_root_symbol(&name_str) {
Some(r) => r.node(), Some(r) => r.node(),
None => self None => self
@ -431,16 +428,10 @@ impl Tree {
_ = tokens.expect_token(Token::Equal)?; _ = tokens.expect_token(Token::Equal)?;
let assignment = { let assignment = self.parse_expr(tokens)?;
let expr = self.parse_expr(tokens)?;
self.nodes.push_tag(Tag::Assign {
lhs: node,
rhs: expr,
})
};
self.nodes.set_node( self.nodes.set_node(
node, decl,
Tag::GlobalDecl { Tag::GlobalDecl {
name, name,
explicit_type, explicit_type,
@ -450,7 +441,7 @@ impl Tree {
tokens.expect_token(Token::Semi)?; tokens.expect_token(Token::Semi)?;
Ok(assignment) Ok(decl)
} }
/// PARAMETER <- /// PARAMETER <-
@ -1103,23 +1094,24 @@ impl Tree {
Tag::VarDecl { Tag::VarDecl {
name, name,
explicit_type, explicit_type,
assignment,
.. ..
} => { } => match (*explicit_type, *assignment) {
if let Some(ty) = *explicit_type { (None, Some(b)) => vec![*name, b],
vec![*name, ty] (Some(a), None) => vec![*name, a],
} else { (Some(a), Some(b)) => vec![*name, a, b],
vec![*name] _ => unreachable!(),
} },
}
Tag::GlobalDecl { Tag::GlobalDecl {
name, name,
explicit_type, explicit_type,
assignment,
.. ..
} => { } => {
if let Some(ty) = *explicit_type { if let Some(ty) = *explicit_type {
vec![*name, ty] vec![*name, ty, *assignment]
} else { } else {
vec![*name] vec![*name, *assignment]
} }
} }
&Tag::CallExpr { lhs, rhs } => { &Tag::CallExpr { lhs, rhs } => {
@ -1279,10 +1271,12 @@ impl Tree {
let_or_var, let_or_var,
name, name,
explicit_type, explicit_type,
.. assignment,
} => { } => {
self.render_node(writer, name, indent)?; self.render_node(writer, name, indent)?;
explicit_type.map(|ty| self.render_node(writer, ty, indent)); explicit_type.map(|node| self.render_node(writer, node, indent));
assignment.map(|node| self.render_node(writer, node, indent));
write_indented!( write_indented!(
indent, indent,
writer, writer,
@ -1301,14 +1295,18 @@ impl Tree {
if let Some(ty) = explicit_type { if let Some(ty) = explicit_type {
write!(writer, ", ty: {}", self.get_typename_str(ty).unwrap())?; write!(writer, ", ty: {}", self.get_typename_str(ty).unwrap())?;
} }
if let Some(assignment) = assignment {
write!(writer, ", value: %{assignment}")?;
}
writeln!(writer, ");")?; writeln!(writer, ");")?;
Ok(()) Ok(())
} }
Tag::GlobalDecl { Tag::GlobalDecl {
name, name,
explicit_type, explicit_type,
.. assignment,
} => { } => {
self.render_node(writer, assignment, indent)?;
self.render_node(writer, name, indent)?; self.render_node(writer, name, indent)?;
explicit_type.map(|ty| self.render_node(writer, ty, indent)); explicit_type.map(|ty| self.render_node(writer, ty, indent));
write_indented!( write_indented!(
@ -1321,6 +1319,7 @@ impl Tree {
if let Some(ty) = explicit_type { if let Some(ty) = explicit_type {
write!(writer, ", ty: {}", self.get_typename_str(ty).unwrap())?; write!(writer, ", ty: {}", self.get_typename_str(ty).unwrap())?;
} }
write!(writer, ", value: %{assignment}")?;
writeln!(writer, ");")?; writeln!(writer, ");")?;
Ok(()) Ok(())
} }
@ -1674,6 +1673,16 @@ impl Tree {
Ok(()) Ok(())
} }
fn render2<W: core::fmt::Write>(&mut self, w: &mut W) {
for decl in self.global_decls.clone().iter() {
ast::tree_visitor::Visitor::new(
*decl,
|_: &mut Tree, _: Node| {},
|_: &mut Tree, _: Node| {},
);
}
}
pub fn peer_type_of_nodes_unwrap(&self, lhs: Node, rhs: Node) -> Type { pub fn peer_type_of_nodes_unwrap(&self, lhs: Node, rhs: Node) -> Type {
self.peer_type_of_nodes(lhs, rhs).expect({ self.peer_type_of_nodes(lhs, rhs).expect({
let at = self.type_of_node(lhs); let at = self.type_of_node(lhs);
@ -1749,8 +1758,7 @@ impl Tree {
assignment, // this is a Tag::Assign assignment, // this is a Tag::Assign
.. ..
} => { } => {
variant!(self.nodes.get_node(*assignment) => Tag::Assign { rhs ,..}); let ty = match (explicit_type.as_ref(), assignment) {
let ty = match (explicit_type.as_ref(), rhs) {
(None, b) => self.type_of_node(*b), (None, b) => self.type_of_node(*b),
(Some(a), b) => self.peer_type_of_nodes(*a, *b).expect({ (Some(a), b) => self.peer_type_of_nodes(*a, *b).expect({
let at = self.type_of_node(*a); let at = self.type_of_node(*a);
@ -1763,13 +1771,10 @@ impl Tree {
} }
Tag::VarDecl { Tag::VarDecl {
explicit_type, explicit_type,
assignment, // this is a Tag::Assign assignment, // this is NOT a Tag::Assign
.. ..
} => { } => {
let rhs = assignment.map(|n| { let rhs = *assignment;
variant!(self.nodes.get_node(n) => Tag::Assign { rhs ,..});
*rhs
});
let ty = match (explicit_type.as_ref(), rhs.as_ref()) { let ty = match (explicit_type.as_ref(), rhs.as_ref()) {
(None, None) => panic!("%{node}: no type specified?"), (None, None) => panic!("%{node}: no type specified?"),
(None, Some(b)) => self.type_of_node(*b), (None, Some(b)) => self.type_of_node(*b),
@ -1830,7 +1835,7 @@ impl Tree {
// simplify tree with compile-time math // simplify tree with compile-time math
impl Tree { impl Tree {
fn is_node_comptime(&self, node: Node, check_declrefs: bool) -> bool { pub fn is_node_comptime(&self, node: Node, check_declrefs: bool) -> bool {
match self.nodes.get_node(node) { match self.nodes.get_node(node) {
Tag::Block { Tag::Block {
statements, statements,
@ -2219,7 +2224,10 @@ impl Tree {
Tag::GlobalDecl { assignment, .. } => { Tag::GlobalDecl { assignment, .. } => {
self.fold_comptime_with_visitor(*assignment); self.fold_comptime_with_visitor(*assignment);
} }
_ => unreachable!(), _ => {
eprintln!("reached %{decl}:");
unreachable!()
}
} }
} }
} }

View file

@ -2,7 +2,7 @@
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap}, collections::{BTreeMap, BTreeSet, HashMap},
}; };
use crate::{ use crate::{
@ -132,6 +132,11 @@ pub enum Inst {
Label, Label,
/// index /// index
FunctionStart, FunctionStart,
/// None
FunctionEnd, // marker
/// Value
/// lhs
GlobalConstant(StringsIndex, Type2),
/// u32 /// u32
ConstantU32, ConstantU32,
/// lo, hi /// lo, hi
@ -372,10 +377,10 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
if value != !0 { if value != !0 {
let ty = self.tree.type_of_node(*body); let ty = self.tree.type_of_node(*body);
self.ir self.ir
.push(Inst::ReturnValue(ty.into()), Some(Data::lhs(value))) .push(Inst::ReturnValue(ty.into()), Some(Data::lhs(value)));
} else {
!0
} }
self.ir.push(Inst::FunctionEnd, None)
} }
Tag::Block { Tag::Block {
statements, statements,
@ -391,21 +396,66 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
!0 !0
} }
} }
Tag::VarDecl { .. } => { Tag::VarDecl { assignment, .. } => {
let ty = self.tree.type_of_node(node); let ty = self.tree.type_of_node(node);
let alloca = self let alloca = self
.ir .ir
.push(Inst::Alloca, Some(Data::new(ty.size_of(), ty.align_of()))); .push(Inst::Alloca, Some(Data::new(ty.size_of(), ty.align_of())));
if let Some(assignment) = assignment {
let value = self.visit(*assignment);
// discard store
let _ = self
.ir
.push(Inst::Store(ty.into()), Some(Data::new(value, alloca)));
}
self.lookup.insert(node, NodeOrList::Node(alloca)); self.lookup.insert(node, NodeOrList::Node(alloca));
alloca alloca
} }
Tag::GlobalDecl { .. } => { Tag::GlobalDecl {
// self.ir.push(Inst::Label, { name, assignment, ..
// variant!(Tag::Ident { name } = self.tree.nodes.get_node(*name)); } => {
// Some((*name).into()) let ty = self.tree.type_of_node(node);
// }); let value = self.visit(*assignment);
unimplemented!() assert!(self.tree.is_node_comptime(*assignment, true));
variant!(self.tree.nodes.get_node(*name) => Tag::Ident { name });
let global = self.ir.push(
Inst::GlobalConstant(*name, ty.into()),
Some(Data::lhs(value)),
);
self.lookup.insert(node, NodeOrList::Node(global));
global
}
Tag::GlobalRef(decl) => {
let node = match self.lookup.get_mut(decl) {
Some(NodeOrList::Node(decl)) => *decl,
lookup => {
println!("lookup for ast decl %{}", decl.get());
println!("{lookup:?}");
panic!("should not have any unresolved lookups")
}
};
node
}
Tag::DeclRef(decl) => match self.lookup.get_mut(decl) {
Some(NodeOrList::Node(decl)) => *decl,
lookup => {
println!("lookup for ast decl %{}", decl.get());
println!("{lookup:?}");
panic!("should not have any unresolved lookups")
}
},
Tag::Assign { lhs, rhs } => {
let ty = self.tree.type_of_node(node);
let dest = self.visit(*lhs);
let source = self.visit(*rhs);
self.ir
.push(Inst::Store(ty.into()), Some(Data::new(source, dest)))
} }
Tag::ReturnStmt { expr } => { Tag::ReturnStmt { expr } => {
if let Some(expr) = expr { if let Some(expr) = expr {
@ -423,14 +473,6 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
let lhs = self.visit(*lhs); let lhs = self.visit(*lhs);
self.ir.push(Inst::Load(ty.into()), Some(Data::lhs(lhs))) self.ir.push(Inst::Load(ty.into()), Some(Data::lhs(lhs)))
} }
Tag::Assign { lhs, rhs } => {
let ty = self.tree.type_of_node(node);
let dest = self.visit(*lhs);
let source = self.visit(*rhs);
self.ir
.push(Inst::Store(ty.into()), Some(Data::new(source, dest)))
}
Tag::Add { lhs, rhs } => { Tag::Add { lhs, rhs } => {
let ty = self.tree.type_of_node(node); let ty = self.tree.type_of_node(node);
let lhs = self.visit(*lhs); let lhs = self.visit(*lhs);
@ -527,15 +569,6 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
self.ir self.ir
.push(Inst::ShiftRight(ty.into()), Some(Data::new(lhs, rhs))) .push(Inst::ShiftRight(ty.into()), Some(Data::new(lhs, rhs)))
} }
Tag::DeclRef(decl) => match self.lookup.get_mut(decl) {
Some(NodeOrList::Node(decl)) => *decl,
lookup => {
println!("lookup for ast decl %{}", decl.get());
println!("{lookup:?}");
panic!("should not have any unresolved lookups")
}
},
Tag::GlobalRef(decl) => self.ir.push(Inst::ExternRef, Some(Data::lhs(decl.get()))),
Tag::Ref { lhs } => { Tag::Ref { lhs } => {
let ty = self.tree.type_of_node(*lhs); let ty = self.tree.type_of_node(*lhs);
let lhs = self.visit(*lhs); let lhs = self.visit(*lhs);
@ -671,6 +704,9 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
let label = self.tree.strings.get_str(data.as_index()); let label = self.tree.strings.get_str(data.as_index());
writeln_indented!(indent - 1, w, "%{} = func {label}:", node)?; writeln_indented!(indent - 1, w, "%{} = func {label}:", node)?;
} }
Inst::FunctionEnd => {
writeln_indented!(indent - 1, w, "end func")?;
}
Inst::Parameter(ty) => { Inst::Parameter(ty) => {
let (size, align) = data.as_lhs_rhs(); let (size, align) = data.as_lhs_rhs();
writeln_indented!( writeln_indented!(
@ -805,6 +841,11 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
let (lhs, rhs) = data.as_lhs_rhs(); let (lhs, rhs) = data.as_lhs_rhs();
writeln_indented!(indent, w, "%{node} = phi [{ty} %{lhs}, {ty} %{rhs}]")?; writeln_indented!(indent, w, "%{node} = phi [{ty} %{lhs}, {ty} %{rhs}]")?;
} }
Inst::GlobalConstant(name, ty) => {
let label = self.tree.strings.get_str(name);
let value = data.lhs;
writeln_indented!(indent, w, "%{node} = global const '{label}' {ty} %{value}")?;
}
_ => { _ => {
unimplemented!("{inst:?} rendering unimplemented") unimplemented!("{inst:?} rendering unimplemented")
} }
@ -1102,6 +1143,39 @@ pub struct MirBuilder<'a> {
ir: IRIter<'a>, ir: IRIter<'a>,
pub strings: StringTable, pub strings: StringTable,
pub functions: HashMap<StringsIndex, mir::Mir>, pub functions: HashMap<StringsIndex, mir::Mir>,
pub globals: HashMap<StringsIndex, mir::Mir>,
}
struct IrToMirMapping<'a> {
ir: &'a IR,
mapping: BTreeMap<Node, mir::NodeRef>,
}
impl<'a> IrToMirMapping<'a> {
fn new(ir: &'a IR) -> Self {
Self {
ir,
mapping: BTreeMap::new(),
}
}
fn insert(&mut self, ir: Node, mir: mir::NodeRef) {
self.mapping.insert(ir, mir);
}
fn get(&mut self, mir: &mut mir::Mir, ir: Node) -> Option<mir::NodeRef> {
if let Some(&mir) = self.mapping.get(&ir) {
return Some(mir);
}
match self.ir.nodes[ir as usize] {
Inst::GlobalConstant(name, ty) => {
let ext = mir::NodeRef(mir.gen_extern(Some(ty.mir_type()), name));
self.insert(ir, ext);
Some(ext)
}
_ => None,
}
}
} }
impl<'a> MirBuilder<'a> { impl<'a> MirBuilder<'a> {
@ -1114,12 +1188,13 @@ impl<'a> MirBuilder<'a> {
}, },
strings, strings,
functions: HashMap::new(), functions: HashMap::new(),
globals: HashMap::new(),
} }
} }
fn build_function(&mut self, name: StringsIndex) { fn build_function(&mut self, name: StringsIndex) {
let mut mir = mir::Mir::new(name); let mut mir = mir::Mir::new(name);
let mut mapping = BTreeMap::<u32, u32>::new(); let mut mapping = IrToMirMapping::new(&self.ir.ir);
// map of label -> unresolved mir jump or branch instruction // map of label -> unresolved mir jump or branch instruction
// stored as a tree of (label, unresolved) // stored as a tree of (label, unresolved)
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
@ -1147,6 +1222,9 @@ impl<'a> MirBuilder<'a> {
self.ir.offset -= 1; self.ir.offset -= 1;
break; break;
} }
Inst::FunctionEnd => {
break;
}
Inst::Label => { Inst::Label => {
let label = mir.gen_label(data.unwrap().as_index()); let label = mir.gen_label(data.unwrap().as_index());
let range = unresolved_jumps_branches let range = unresolved_jumps_branches
@ -1220,20 +1298,20 @@ impl<'a> MirBuilder<'a> {
} }
Inst::Load(ty) => { Inst::Load(ty) => {
let ty = mir::Type::from_bytesize_int(ty.size()); let ty = mir::Type::from_bytesize_int(ty.size());
let src = *mapping.get(&data.unwrap().as_u32()).unwrap(); let src = mapping.get(&mut mir, data.unwrap().as_u32()).unwrap().0;
mir.gen_load(ty, src) mir.gen_load(ty, src)
} }
Inst::Store(ty) => { Inst::Store(ty) => {
let ty = mir::Type::from_bytesize_int(ty.size()); let ty = mir::Type::from_bytesize_int(ty.size());
let (src, dst) = data.unwrap().as_lhs_rhs(); let (src, dst) = data.unwrap().as_lhs_rhs();
let src = *mapping.get(&src).unwrap(); let src = mapping.get(&mut mir, src).unwrap().0;
let dst = *mapping.get(&dst).unwrap(); let dst = mapping.get(&mut mir, dst).unwrap().0;
mir.gen_store(ty, src, dst) mir.gen_store(ty, src, dst)
} }
Inst::GetElementPtr(ty) => { Inst::GetElementPtr(ty) => {
let ty = mir::Type::from_bytesize_int(ty.size()); let ty = mir::Type::from_bytesize_int(ty.size());
let (ptr, idx) = data.unwrap().as_lhs_rhs(); let (ptr, idx) = data.unwrap().as_lhs_rhs();
let src = *mapping.get(&ptr).unwrap(); let src = mapping.get(&mut mir, ptr).unwrap().0;
mir.gen_get_element_ptr(ty, src, idx) mir.gen_get_element_ptr(ty, src, idx)
} }
Inst::Parameter(ty) => { Inst::Parameter(ty) => {
@ -1247,8 +1325,8 @@ impl<'a> MirBuilder<'a> {
| Inst::Ge(ty) | Inst::Ge(ty)
| Inst::Le(ty) => { | Inst::Le(ty) => {
let (src, dst) = data.unwrap().as_lhs_rhs(); let (src, dst) = data.unwrap().as_lhs_rhs();
let lhs = *mapping.get(&src).unwrap(); let lhs = mapping.get(&mut mir, src).unwrap().0;
let rhs = *mapping.get(&dst).unwrap(); let rhs = mapping.get(&mut mir, dst).unwrap().0;
#[cfg_attr(rustfmt, rustfmt::skip)] #[cfg_attr(rustfmt, rustfmt::skip)]
let (ord, invert)= match inst { let (ord, invert)= match inst {
@ -1265,8 +1343,8 @@ impl<'a> MirBuilder<'a> {
} }
Inst::Add(ty) => { Inst::Add(ty) => {
let (src, dst) = data.unwrap().as_lhs_rhs(); let (src, dst) = data.unwrap().as_lhs_rhs();
let lhs = *mapping.get(&src).unwrap(); let lhs = mapping.get(&mut mir, src).unwrap().0;
let rhs = *mapping.get(&dst).unwrap(); let rhs = mapping.get(&mut mir, dst).unwrap().0;
match ty { match ty {
Type2::Integral(signed, bits) => match bits { Type2::Integral(signed, bits) => match bits {
@ -1292,8 +1370,8 @@ impl<'a> MirBuilder<'a> {
} }
Inst::Sub(ty) => { Inst::Sub(ty) => {
let (src, dst) = data.unwrap().as_lhs_rhs(); let (src, dst) = data.unwrap().as_lhs_rhs();
let lhs = *mapping.get(&src).unwrap(); let lhs = mapping.get(&mut mir, src).unwrap().0;
let rhs = *mapping.get(&dst).unwrap(); let rhs = mapping.get(&mut mir, dst).unwrap().0;
let unalignment = ty.mir_unalignment(); let unalignment = ty.mir_unalignment();
let ty = ty.mir_type(); let ty = ty.mir_type();
@ -1312,8 +1390,8 @@ impl<'a> MirBuilder<'a> {
let signed = ty.is_signed(); let signed = ty.is_signed();
let ty = ty.mir_type(); let ty = ty.mir_type();
let lhs = *mapping.get(&lhs).unwrap(); let lhs = mapping.get(&mut mir, lhs).unwrap().0;
let rhs = *mapping.get(&rhs).unwrap(); let rhs = mapping.get(&mut mir, rhs).unwrap().0;
let sum = mir.gen_mul(ty, signed, lhs, rhs); let sum = mir.gen_mul(ty, signed, lhs, rhs);
if let Some((signed, bits)) = unalignment { if let Some((signed, bits)) = unalignment {
@ -1329,8 +1407,8 @@ impl<'a> MirBuilder<'a> {
let signed = ty.is_signed(); let signed = ty.is_signed();
let ty = ty.mir_type(); let ty = ty.mir_type();
let lhs = *mapping.get(&lhs).unwrap(); let lhs = mapping.get(&mut mir, lhs).unwrap().0;
let rhs = *mapping.get(&rhs).unwrap(); let rhs = mapping.get(&mut mir, rhs).unwrap().0;
let sum = mir.gen_div(ty, signed, lhs, rhs); let sum = mir.gen_div(ty, signed, lhs, rhs);
if let Some((signed, bits)) = unalignment { if let Some((signed, bits)) = unalignment {
@ -1346,8 +1424,8 @@ impl<'a> MirBuilder<'a> {
let signed = ty.is_signed(); let signed = ty.is_signed();
let ty = ty.mir_type(); let ty = ty.mir_type();
let lhs = *mapping.get(&lhs).unwrap(); let lhs = mapping.get(&mut mir, lhs).unwrap().0;
let rhs = *mapping.get(&rhs).unwrap(); let rhs = mapping.get(&mut mir, rhs).unwrap().0;
let sum = mir.gen_rem(ty, signed, lhs, rhs); let sum = mir.gen_rem(ty, signed, lhs, rhs);
if let Some((signed, bits)) = unalignment { if let Some((signed, bits)) = unalignment {
@ -1368,8 +1446,8 @@ impl<'a> MirBuilder<'a> {
(lhs, rhs) (lhs, rhs)
}; };
let lhs = *mapping.get(&lhs).unwrap(); let lhs = mapping.get(&mut mir, lhs).unwrap().0;
let rhs = *mapping.get(&rhs).unwrap(); let rhs = mapping.get(&mut mir, rhs).unwrap().0;
let sum = mir.gen_bitand(ty, lhs, rhs); let sum = mir.gen_bitand(ty, lhs, rhs);
if let Some((signed, bits)) = unalignment { if let Some((signed, bits)) = unalignment {
@ -1390,8 +1468,8 @@ impl<'a> MirBuilder<'a> {
(lhs, rhs) (lhs, rhs)
}; };
let lhs = *mapping.get(&lhs).unwrap(); let lhs = mapping.get(&mut mir, lhs).unwrap().0;
let rhs = *mapping.get(&rhs).unwrap(); let rhs = mapping.get(&mut mir, rhs).unwrap().0;
let sum = mir.gen_bitor(ty, lhs, rhs); let sum = mir.gen_bitor(ty, lhs, rhs);
if let Some((signed, bits)) = unalignment { if let Some((signed, bits)) = unalignment {
@ -1412,8 +1490,8 @@ impl<'a> MirBuilder<'a> {
(lhs, rhs) (lhs, rhs)
}; };
let lhs = *mapping.get(&lhs).unwrap(); let lhs = mapping.get(&mut mir, lhs).unwrap().0;
let rhs = *mapping.get(&rhs).unwrap(); let rhs = mapping.get(&mut mir, rhs).unwrap().0;
let sum = mir.gen_bitxor(ty, lhs, rhs); let sum = mir.gen_bitxor(ty, lhs, rhs);
if let Some((signed, bits)) = unalignment { if let Some((signed, bits)) = unalignment {
@ -1424,8 +1502,8 @@ impl<'a> MirBuilder<'a> {
} }
Inst::ShiftLeft(ty) => { Inst::ShiftLeft(ty) => {
let (src, dst) = data.unwrap().as_lhs_rhs(); let (src, dst) = data.unwrap().as_lhs_rhs();
let lhs = *mapping.get(&src).unwrap(); let lhs = mapping.get(&mut mir, src).unwrap().0;
let rhs = *mapping.get(&dst).unwrap(); let rhs = mapping.get(&mut mir, dst).unwrap().0;
// TODO: check rhs type and pass it to gen_sh{l,r}? // TODO: check rhs type and pass it to gen_sh{l,r}?
let rhs = mir.gen_truncate_integer(rhs, ty.into(), false, 8); let rhs = mir.gen_truncate_integer(rhs, ty.into(), false, 8);
@ -1450,8 +1528,8 @@ impl<'a> MirBuilder<'a> {
} }
Inst::ShiftRight(ty) => { Inst::ShiftRight(ty) => {
let (src, dst) = data.unwrap().as_lhs_rhs(); let (src, dst) = data.unwrap().as_lhs_rhs();
let lhs = *mapping.get(&src).unwrap(); let lhs = mapping.get(&mut mir, src).unwrap().0;
let rhs = *mapping.get(&dst).unwrap(); let rhs = mapping.get(&mut mir, dst).unwrap().0;
match ty { match ty {
Type2::Integral(signed, bits) => match bits { Type2::Integral(signed, bits) => match bits {
@ -1487,7 +1565,7 @@ impl<'a> MirBuilder<'a> {
let unalignment = ty.mir_unalignment(); let unalignment = ty.mir_unalignment();
let ty = ty.mir_type(); let ty = ty.mir_type();
let lhs = *mapping.get(&lhs).unwrap(); let lhs = mapping.get(&mut mir, lhs).unwrap().0;
let sum = mir.gen_not(ty, lhs); let sum = mir.gen_not(ty, lhs);
if let Some((signed, bits)) = unalignment { if let Some((signed, bits)) = unalignment {
@ -1502,7 +1580,7 @@ impl<'a> MirBuilder<'a> {
let unalignment = ty.mir_unalignment(); let unalignment = ty.mir_unalignment();
let ty = ty.mir_type(); let ty = ty.mir_type();
let lhs = *mapping.get(&lhs).unwrap(); let lhs = mapping.get(&mut mir, lhs).unwrap().0;
let sum = mir.gen_negate(ty, lhs); let sum = mir.gen_negate(ty, lhs);
if let Some((signed, bits)) = unalignment { if let Some((signed, bits)) = unalignment {
@ -1516,7 +1594,7 @@ impl<'a> MirBuilder<'a> {
let from_mir = from.mir_type(); let from_mir = from.mir_type();
let to_mir = to.mir_type(); let to_mir = to.mir_type();
let lhs = *mapping.get(&lhs).unwrap(); let lhs = mapping.get(&mut mir, lhs).unwrap().0;
match (from, to) { match (from, to) {
(Type2::Integral(a_signed, a), Type2::Integral(b_signed, b)) => { (Type2::Integral(a_signed, a), Type2::Integral(b_signed, b)) => {
@ -1546,7 +1624,7 @@ impl<'a> MirBuilder<'a> {
} }
Inst::ReturnValue(ty) => { Inst::ReturnValue(ty) => {
let src = data.unwrap().as_u32(); let src = data.unwrap().as_u32();
let src = *mapping.get(&src).unwrap(); let src = mapping.get(&mut mir, src).unwrap().0;
mir.gen_ret_val(ty.mir_type(), src) mir.gen_ret_val(ty.mir_type(), src)
} }
@ -1556,8 +1634,8 @@ impl<'a> MirBuilder<'a> {
let jmp = mir.gen_jmp(label); let jmp = mir.gen_jmp(label);
let label = match mapping.get(&label) { let label = match mapping.get(&mut mir, label) {
Some(&label) => label, Some(label) => label.0,
None => { None => {
unresolved_jumps_branches unresolved_jumps_branches
.insert((label, LeftRight::Left(mir::NodeRef(jmp)))); .insert((label, LeftRight::Left(mir::NodeRef(jmp))));
@ -1570,21 +1648,21 @@ impl<'a> MirBuilder<'a> {
jmp jmp
} }
Inst::Branch(condition) => { Inst::Branch(condition) => {
let condition = *mapping.get(&condition).unwrap(); let condition = mapping.get(&mut mir, condition).unwrap().0;
let (lhs, rhs) = data.unwrap().as_lhs_rhs(); let (lhs, rhs) = data.unwrap().as_lhs_rhs();
let br = mir.gen_branch(condition, lhs, rhs); let br = mir.gen_branch(condition, lhs, rhs);
let lhs = match mapping.get(&lhs) { let lhs = match mapping.get(&mut mir, lhs) {
Some(&n) => n, Some(n) => n.0,
None => { None => {
unresolved_jumps_branches unresolved_jumps_branches
.insert((lhs, LeftRight::Left(mir::NodeRef(br)))); .insert((lhs, LeftRight::Left(mir::NodeRef(br))));
0 0
} }
}; };
let rhs = match mapping.get(&rhs) { let rhs = match mapping.get(&mut mir, rhs) {
Some(&n) => n, Some(n) => n.0,
None => { None => {
unresolved_jumps_branches unresolved_jumps_branches
.insert((rhs, LeftRight::Right(mir::NodeRef(br)))); .insert((rhs, LeftRight::Right(mir::NodeRef(br))));
@ -1598,18 +1676,24 @@ impl<'a> MirBuilder<'a> {
} }
Inst::Phi2(ty) => { Inst::Phi2(ty) => {
let (src, dst) = data.unwrap().as_lhs_rhs(); let (src, dst) = data.unwrap().as_lhs_rhs();
let lhs = *mapping.get(&src).unwrap(); let lhs = mapping.get(&mut mir, src).unwrap().0;
let rhs = *mapping.get(&dst).unwrap(); let rhs = mapping.get(&mut mir, dst).unwrap().0;
mir.gen_phi2(ty.mir_type(), lhs, rhs) mir.gen_phi2(ty.mir_type(), lhs, rhs)
} }
Inst::GlobalConstant(name, ty) => {
let ext = mir.gen_extern(Some(ty.mir_type()), name);
ext
}
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]
_ => { _ => {
eprintln!("ir inst {inst:?} not supported in mir translation");
unimplemented!() unimplemented!()
} }
}; };
mapping.insert(ir_node, node); mapping.insert(ir_node, mir::NodeRef(node));
} }
self.functions.insert(name, mir); self.functions.insert(name, mir);
@ -1622,6 +1706,50 @@ impl<'a> MirBuilder<'a> {
}; };
match inst { match inst {
Inst::FunctionStart => self.build_function(data.unwrap().as_index()), Inst::FunctionStart => self.build_function(data.unwrap().as_index()),
Inst::GlobalConstant(name, ..) => {
let mut mir = mir::Mir::new(name);
let value = data.unwrap().lhs;
let data = self.ir.ir.data[value as usize];
let inst = self.ir.ir.nodes[value as usize];
let _value = match inst {
Inst::ConstantU32 => mir.push(
mir::Inst::ConstantDWord,
mir::Data::imm32(data.unwrap().as_u32()),
),
Inst::ConstantU64 => mir.push(
mir::Inst::ConstantQWord,
mir::Data::imm64(data.unwrap().as_u64()),
),
Inst::ConstantMultiByte => {
let bytes = self.strings.get_bytes(data.unwrap().as_index());
let mut buf = [0u8; 8];
match bytes.len() {
1 => mir.gen_u8(bytes[0]),
2 => {
mir.gen_u16(u16::from_le_bytes(bytes[..2].try_into().unwrap()))
}
3..=4 => {
buf[..bytes.len()].copy_from_slice(bytes);
mir.gen_u32(u32::from_le_bytes(buf[..4].try_into().unwrap()))
}
5..=8 => {
buf[..bytes.len()].copy_from_slice(bytes);
mir.gen_u64(u64::from_le_bytes(buf[..8].try_into().unwrap()))
}
_ => {
unimplemented!(
"constants larger than 8 bytes are not currently supported!"
)
}
}
}
_ => {
unimplemented!()
}
};
self.globals.insert(name, mir);
}
_ => {} _ => {}
} }
} }
@ -1634,51 +1762,6 @@ mod tests {
use super::*; use super::*;
#[test]
fn mir() {
let src = "
fn inverse_sqrt(x: f32) -> f32 {
let three_halfs: f32 = 1.5f32;
let x2 = x * 0.5f32;
var y = x;
let i = 0x5f3759dfu32 - (*(&y as *u32) >> 1u32);
y = *(&i as *f32);
y = y * (three_halfs - (x2 * y * y));
return y;
}
";
let tokens = Tokenizer::new(src.as_bytes()).unwrap();
let mut tree = Tree::new();
tree.parse(tokens.iter()).unwrap();
tree.fold_comptime();
let mut buf = String::new();
tree.render(&mut buf).unwrap();
println!("AST:\n{buf}");
let mut ir = IR::new();
let builder = ir.build(&mut tree);
let mut buf = String::new();
builder.render(&mut buf).unwrap();
println!("IR:\n{buf}");
let mut mir = MirBuilder::new(&ir, tree.strings);
mir.build();
let MirBuilder {
strings, functions, ..
} = mir;
for (_name, mir) in functions {
let assembly = mir.assemble(&strings).unwrap();
println!("mir:\n{}", mir.display(&strings));
println!("assembly:\n{assembly}");
}
}
#[test] #[test]
fn mir_u10() { fn mir_u10() {
let src = " let src = "