global symbols
This commit is contained in:
parent
4b432f404b
commit
4424ef875d
|
@ -77,13 +77,28 @@ fn main() {
|
|||
mir.build();
|
||||
|
||||
let MirBuilder {
|
||||
strings, functions, ..
|
||||
globals,
|
||||
strings,
|
||||
functions,
|
||||
..
|
||||
} = mir;
|
||||
|
||||
println!(".intel_syntax");
|
||||
println!(".text");
|
||||
for (_name, mir) in globals {
|
||||
let assembly = mir
|
||||
.assemble(&strings)
|
||||
.unwrap()
|
||||
.finish_constants(&strings)
|
||||
.unwrap();
|
||||
println!("{assembly}");
|
||||
}
|
||||
for (_name, mir) in functions {
|
||||
let assembly = mir.assemble(&strings).unwrap();
|
||||
let assembly = mir
|
||||
.assemble(&strings)
|
||||
.unwrap()
|
||||
.finish_as_function(&strings)
|
||||
.unwrap();
|
||||
println!("{assembly}");
|
||||
}
|
||||
}
|
||||
|
|
227
src/mir.rs
227
src/mir.rs
|
@ -2,14 +2,13 @@
|
|||
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::btree_map::Entry;
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::fmt::Display;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter::FusedIterator;
|
||||
use std::u32;
|
||||
|
||||
use itertools::Itertools;
|
||||
use liveness::LivenessBuilder;
|
||||
|
||||
use crate::asm::amd64::Register;
|
||||
use crate::ast::IntegralType;
|
||||
|
@ -138,8 +137,8 @@ pub enum Inst {
|
|||
ConstantDoublePrecision,
|
||||
/// src
|
||||
LoadRegister(Type), // hint for loading value into register
|
||||
/// ast-node
|
||||
ExternRef,
|
||||
/// index
|
||||
ExternRef(Option<Type>), // might have a type, or might be a name only,
|
||||
/// size, align
|
||||
Alloca,
|
||||
/// src
|
||||
|
@ -224,9 +223,9 @@ pub enum Inst {
|
|||
impl Inst {
|
||||
fn value_type(&self) -> Option<Type> {
|
||||
match self {
|
||||
Inst::ExternRef(ty) => *ty,
|
||||
Inst::Label
|
||||
| Inst::ConstantBytes
|
||||
| Inst::ExternRef
|
||||
| Inst::Alloca
|
||||
| Inst::ReturnValue(_)
|
||||
| Inst::Store(_)
|
||||
|
@ -290,7 +289,7 @@ impl Inst {
|
|||
| Inst::ConstantQWord
|
||||
| Inst::ConstantSinglePrecision
|
||||
| Inst::ConstantDoublePrecision
|
||||
| Inst::ExternRef
|
||||
| Inst::ExternRef(_)
|
||||
| Inst::Alloca
|
||||
| Inst::Store(_)
|
||||
| Inst::ReturnValue(_)
|
||||
|
@ -950,6 +949,9 @@ impl Mir {
|
|||
pub fn gen_label(&mut self, name: StringsIndex) -> u32 {
|
||||
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 {
|
||||
self.push(Inst::Alloca, Data::binary(size, align))
|
||||
}
|
||||
|
@ -1190,7 +1192,13 @@ impl Mir {
|
|||
let src = data.as_node();
|
||||
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 => {
|
||||
let (size, align) = data.as_binary();
|
||||
writeln!(w, "%{node} = alloca {size}, {align}")
|
||||
|
@ -1497,9 +1505,6 @@ pub mod liveness {
|
|||
|
||||
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| {
|
||||
|
@ -1530,9 +1535,6 @@ pub mod liveness {
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
eprintln!("intervals: {intervals:#?}");
|
||||
eprintln!("edges: {edges:#?}");
|
||||
|
||||
// build interference graph with mutliple branches.
|
||||
// BTreeMap<MirRange, Interferencegraph>
|
||||
type Edge = (NodeRef, NodeRef);
|
||||
|
@ -1562,8 +1564,6 @@ pub mod liveness {
|
|||
}
|
||||
}
|
||||
|
||||
eprintln!("per_branch_edges: {per_branch_edges:?}");
|
||||
|
||||
let branches = per_branch_edges
|
||||
.into_iter()
|
||||
.map(|(range, edges)| {
|
||||
|
@ -1573,7 +1573,6 @@ pub mod liveness {
|
|||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
eprintln!("branches: {branches:#?}");
|
||||
|
||||
Self {
|
||||
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> {
|
||||
mir: &'a Mir,
|
||||
// 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)]
|
||||
enum Color {
|
||||
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)> {
|
||||
let mut references = BTreeSet::new();
|
||||
for node in mir.indices() {
|
||||
|
@ -2008,10 +1889,10 @@ pub mod liveness {
|
|||
.cloned()
|
||||
.collect::<BTreeSet<_>>();
|
||||
|
||||
eprintln!("coloring %{node_u32}:");
|
||||
eprintln!("\twants: {:?}", self.colors.get(&node_ref));
|
||||
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(node_ref) {
|
||||
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
|
||||
// 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) {
|
||||
eprintln!("coloring {inputs:?} {color}");
|
||||
for node in inputs {
|
||||
_ = self.colors.insert(node, Color::Tentative(color));
|
||||
}
|
||||
|
@ -2139,7 +2019,7 @@ impl Mir {
|
|||
| Inst::ConstantQWord
|
||||
| Inst::ConstantSinglePrecision
|
||||
| Inst::ConstantDoublePrecision
|
||||
| Inst::ExternRef
|
||||
| Inst::ExternRef(_)
|
||||
| Inst::Alloca => {}
|
||||
}
|
||||
}
|
||||
|
@ -2191,7 +2071,7 @@ impl Mir {
|
|||
| Inst::ConstantQWord
|
||||
| Inst::ConstantSinglePrecision
|
||||
| Inst::ConstantDoublePrecision
|
||||
| Inst::ExternRef
|
||||
| Inst::ExternRef(_)
|
||||
| Inst::Alloca
|
||||
| Inst::Jump
|
||||
| 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)]
|
||||
fn dirty_register(&mut self, reg: Register) {
|
||||
self.dirty_registers.insert(reg);
|
||||
|
@ -2436,10 +2337,15 @@ impl Function {
|
|||
writeln!(w, "push {reg}")?;
|
||||
}
|
||||
|
||||
writeln!(w, "push rbp")?;
|
||||
writeln!(w, "mov rbp, rsp")?;
|
||||
writeln!(w, "sub rsp, {}", self.stack_offset)?;
|
||||
let needs_frame = !saved_registers.is_empty() && self.stack_offset != 0;
|
||||
|
||||
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())?;
|
||||
|
||||
for (branch, content) in &self.branches {
|
||||
|
@ -2448,12 +2354,16 @@ impl Function {
|
|||
}
|
||||
|
||||
writeln!(w, ".{name}__epilogue:")?;
|
||||
writeln!(w, "mov rsp, rbp")?;
|
||||
writeln!(w, "pop rbp")?;
|
||||
|
||||
for reg in saved_registers.iter().rev() {
|
||||
writeln!(w, "pop {reg}")?;
|
||||
if needs_frame {
|
||||
writeln!(w, "mov rsp, rbp")?;
|
||||
writeln!(w, "pop rbp")?;
|
||||
|
||||
for reg in saved_registers.iter().rev() {
|
||||
writeln!(w, "pop {reg}")?;
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(w, "ret")?;
|
||||
|
||||
Ok(())
|
||||
|
@ -2542,14 +2452,20 @@ impl Mir {
|
|||
let (offset, size) = *mapping.get(&(node as usize)).unwrap();
|
||||
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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
// mapping if (i, (stack_offset, bytes)) for local stack variables
|
||||
let mut mapping = BTreeMap::<usize, (u32, u32)>::new();
|
||||
|
@ -2574,7 +2490,9 @@ impl Mir {
|
|||
| Inst::ConstantByte
|
||||
| Inst::ConstantWord
|
||||
| Inst::ConstantDWord
|
||||
| Inst::ConstantQWord => {}
|
||||
| Inst::ConstantQWord => {
|
||||
func.add_constant_from_inst_and_data(i, inst, data, strings);
|
||||
}
|
||||
Inst::ConstantSinglePrecision => {
|
||||
let bits = data.as_imm32();
|
||||
func.add_constant(i, format!(".long {bits}"));
|
||||
|
@ -2631,7 +2549,7 @@ impl Mir {
|
|||
writeln!(func.current_branch(), "mov {dst}, {src}",)?;
|
||||
}
|
||||
}
|
||||
Inst::ExternRef => todo!(),
|
||||
Inst::ExternRef(_) => {}
|
||||
Inst::Alloca => {
|
||||
let (size, align) = data.as_binary();
|
||||
let offset = func.alloca(size, align);
|
||||
|
@ -3553,10 +3471,7 @@ impl Mir {
|
|||
}
|
||||
}
|
||||
|
||||
let mut buf = String::new();
|
||||
func.finish(&mut buf, strings)?;
|
||||
|
||||
Ok(buf)
|
||||
Ok(func)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -374,24 +374,19 @@ impl Tree {
|
|||
};
|
||||
|
||||
let name_str = self.strings.get_str(self.ident_index(name)).to_owned();
|
||||
let node = {
|
||||
let node = self.nodes.reserve_node();
|
||||
self.st.insert_symbol(&name_str, node, SymbolKind::Var);
|
||||
node
|
||||
};
|
||||
let decl = self.nodes.reserve_node();
|
||||
|
||||
let assignment = if tokens.eat_token(Token::Equal).is_some() {
|
||||
let expr = self.parse_expr(tokens)?;
|
||||
Some(self.nodes.push_tag(Tag::Assign {
|
||||
lhs: node,
|
||||
rhs: expr,
|
||||
}))
|
||||
Some(self.parse_expr(tokens)?)
|
||||
} else {
|
||||
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(
|
||||
node,
|
||||
decl,
|
||||
Tag::VarDecl {
|
||||
let_or_var,
|
||||
name,
|
||||
|
@ -401,7 +396,7 @@ impl Tree {
|
|||
);
|
||||
|
||||
// return assignment if it exists, to make rendering and visiting easier
|
||||
Ok(assignment.unwrap_or(node))
|
||||
Ok(decl)
|
||||
}
|
||||
|
||||
/// GLOBAL_DECL <-
|
||||
|
@ -418,7 +413,9 @@ impl Tree {
|
|||
};
|
||||
|
||||
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) {
|
||||
Some(r) => r.node(),
|
||||
None => self
|
||||
|
@ -431,16 +428,10 @@ impl Tree {
|
|||
|
||||
_ = tokens.expect_token(Token::Equal)?;
|
||||
|
||||
let assignment = {
|
||||
let expr = self.parse_expr(tokens)?;
|
||||
self.nodes.push_tag(Tag::Assign {
|
||||
lhs: node,
|
||||
rhs: expr,
|
||||
})
|
||||
};
|
||||
let assignment = self.parse_expr(tokens)?;
|
||||
|
||||
self.nodes.set_node(
|
||||
node,
|
||||
decl,
|
||||
Tag::GlobalDecl {
|
||||
name,
|
||||
explicit_type,
|
||||
|
@ -450,7 +441,7 @@ impl Tree {
|
|||
|
||||
tokens.expect_token(Token::Semi)?;
|
||||
|
||||
Ok(assignment)
|
||||
Ok(decl)
|
||||
}
|
||||
|
||||
/// PARAMETER <-
|
||||
|
@ -1103,23 +1094,24 @@ impl Tree {
|
|||
Tag::VarDecl {
|
||||
name,
|
||||
explicit_type,
|
||||
assignment,
|
||||
..
|
||||
} => {
|
||||
if let Some(ty) = *explicit_type {
|
||||
vec![*name, ty]
|
||||
} else {
|
||||
vec![*name]
|
||||
}
|
||||
}
|
||||
} => match (*explicit_type, *assignment) {
|
||||
(None, Some(b)) => vec![*name, b],
|
||||
(Some(a), None) => vec![*name, a],
|
||||
(Some(a), Some(b)) => vec![*name, a, b],
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Tag::GlobalDecl {
|
||||
name,
|
||||
explicit_type,
|
||||
assignment,
|
||||
..
|
||||
} => {
|
||||
if let Some(ty) = *explicit_type {
|
||||
vec![*name, ty]
|
||||
vec![*name, ty, *assignment]
|
||||
} else {
|
||||
vec![*name]
|
||||
vec![*name, *assignment]
|
||||
}
|
||||
}
|
||||
&Tag::CallExpr { lhs, rhs } => {
|
||||
|
@ -1279,10 +1271,12 @@ impl Tree {
|
|||
let_or_var,
|
||||
name,
|
||||
explicit_type,
|
||||
..
|
||||
assignment,
|
||||
} => {
|
||||
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!(
|
||||
indent,
|
||||
writer,
|
||||
|
@ -1301,14 +1295,18 @@ impl Tree {
|
|||
if let Some(ty) = explicit_type {
|
||||
write!(writer, ", ty: {}", self.get_typename_str(ty).unwrap())?;
|
||||
}
|
||||
if let Some(assignment) = assignment {
|
||||
write!(writer, ", value: %{assignment}")?;
|
||||
}
|
||||
writeln!(writer, ");")?;
|
||||
Ok(())
|
||||
}
|
||||
Tag::GlobalDecl {
|
||||
name,
|
||||
explicit_type,
|
||||
..
|
||||
assignment,
|
||||
} => {
|
||||
self.render_node(writer, assignment, indent)?;
|
||||
self.render_node(writer, name, indent)?;
|
||||
explicit_type.map(|ty| self.render_node(writer, ty, indent));
|
||||
write_indented!(
|
||||
|
@ -1321,6 +1319,7 @@ impl Tree {
|
|||
if let Some(ty) = explicit_type {
|
||||
write!(writer, ", ty: {}", self.get_typename_str(ty).unwrap())?;
|
||||
}
|
||||
write!(writer, ", value: %{assignment}")?;
|
||||
writeln!(writer, ");")?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1674,6 +1673,16 @@ impl Tree {
|
|||
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 {
|
||||
self.peer_type_of_nodes(lhs, rhs).expect({
|
||||
let at = self.type_of_node(lhs);
|
||||
|
@ -1749,8 +1758,7 @@ impl Tree {
|
|||
assignment, // this is a Tag::Assign
|
||||
..
|
||||
} => {
|
||||
variant!(self.nodes.get_node(*assignment) => Tag::Assign { rhs ,..});
|
||||
let ty = match (explicit_type.as_ref(), rhs) {
|
||||
let ty = match (explicit_type.as_ref(), assignment) {
|
||||
(None, b) => self.type_of_node(*b),
|
||||
(Some(a), b) => self.peer_type_of_nodes(*a, *b).expect({
|
||||
let at = self.type_of_node(*a);
|
||||
|
@ -1763,13 +1771,10 @@ impl Tree {
|
|||
}
|
||||
Tag::VarDecl {
|
||||
explicit_type,
|
||||
assignment, // this is a Tag::Assign
|
||||
assignment, // this is NOT a Tag::Assign
|
||||
..
|
||||
} => {
|
||||
let rhs = assignment.map(|n| {
|
||||
variant!(self.nodes.get_node(n) => Tag::Assign { rhs ,..});
|
||||
*rhs
|
||||
});
|
||||
let rhs = *assignment;
|
||||
let ty = match (explicit_type.as_ref(), rhs.as_ref()) {
|
||||
(None, None) => panic!("%{node}: no type specified?"),
|
||||
(None, Some(b)) => self.type_of_node(*b),
|
||||
|
@ -1830,7 +1835,7 @@ impl Tree {
|
|||
|
||||
// simplify tree with compile-time math
|
||||
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) {
|
||||
Tag::Block {
|
||||
statements,
|
||||
|
@ -2219,7 +2224,10 @@ impl Tree {
|
|||
Tag::GlobalDecl { assignment, .. } => {
|
||||
self.fold_comptime_with_visitor(*assignment);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
_ => {
|
||||
eprintln!("reached %{decl}:");
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
311
src/triples.rs
311
src/triples.rs
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap},
|
||||
collections::{BTreeMap, BTreeSet, HashMap},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -132,6 +132,11 @@ pub enum Inst {
|
|||
Label,
|
||||
/// index
|
||||
FunctionStart,
|
||||
/// None
|
||||
FunctionEnd, // marker
|
||||
/// Value
|
||||
/// lhs
|
||||
GlobalConstant(StringsIndex, Type2),
|
||||
/// u32
|
||||
ConstantU32,
|
||||
/// lo, hi
|
||||
|
@ -372,10 +377,10 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
|||
if value != !0 {
|
||||
let ty = self.tree.type_of_node(*body);
|
||||
self.ir
|
||||
.push(Inst::ReturnValue(ty.into()), Some(Data::lhs(value)))
|
||||
} else {
|
||||
!0
|
||||
.push(Inst::ReturnValue(ty.into()), Some(Data::lhs(value)));
|
||||
}
|
||||
|
||||
self.ir.push(Inst::FunctionEnd, None)
|
||||
}
|
||||
Tag::Block {
|
||||
statements,
|
||||
|
@ -391,21 +396,66 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
|||
!0
|
||||
}
|
||||
}
|
||||
Tag::VarDecl { .. } => {
|
||||
Tag::VarDecl { assignment, .. } => {
|
||||
let ty = self.tree.type_of_node(node);
|
||||
let alloca = self
|
||||
.ir
|
||||
.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));
|
||||
alloca
|
||||
}
|
||||
Tag::GlobalDecl { .. } => {
|
||||
// self.ir.push(Inst::Label, {
|
||||
// variant!(Tag::Ident { name } = self.tree.nodes.get_node(*name));
|
||||
// Some((*name).into())
|
||||
// });
|
||||
unimplemented!()
|
||||
Tag::GlobalDecl {
|
||||
name, assignment, ..
|
||||
} => {
|
||||
let ty = self.tree.type_of_node(node);
|
||||
let value = self.visit(*assignment);
|
||||
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 } => {
|
||||
if let Some(expr) = expr {
|
||||
|
@ -423,14 +473,6 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
|||
let lhs = self.visit(*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 } => {
|
||||
let ty = self.tree.type_of_node(node);
|
||||
let lhs = self.visit(*lhs);
|
||||
|
@ -527,15 +569,6 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
|||
self.ir
|
||||
.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 } => {
|
||||
let ty = self.tree.type_of_node(*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());
|
||||
writeln_indented!(indent - 1, w, "%{} = func {label}:", node)?;
|
||||
}
|
||||
Inst::FunctionEnd => {
|
||||
writeln_indented!(indent - 1, w, "end func")?;
|
||||
}
|
||||
Inst::Parameter(ty) => {
|
||||
let (size, align) = data.as_lhs_rhs();
|
||||
writeln_indented!(
|
||||
|
@ -805,6 +841,11 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
|
|||
let (lhs, rhs) = data.as_lhs_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")
|
||||
}
|
||||
|
@ -1102,6 +1143,39 @@ pub struct MirBuilder<'a> {
|
|||
ir: IRIter<'a>,
|
||||
pub strings: StringTable,
|
||||
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> {
|
||||
|
@ -1114,12 +1188,13 @@ impl<'a> MirBuilder<'a> {
|
|||
},
|
||||
strings,
|
||||
functions: HashMap::new(),
|
||||
globals: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_function(&mut self, name: StringsIndex) {
|
||||
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
|
||||
// stored as a tree of (label, unresolved)
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
|
@ -1147,6 +1222,9 @@ impl<'a> MirBuilder<'a> {
|
|||
self.ir.offset -= 1;
|
||||
break;
|
||||
}
|
||||
Inst::FunctionEnd => {
|
||||
break;
|
||||
}
|
||||
Inst::Label => {
|
||||
let label = mir.gen_label(data.unwrap().as_index());
|
||||
let range = unresolved_jumps_branches
|
||||
|
@ -1220,20 +1298,20 @@ impl<'a> MirBuilder<'a> {
|
|||
}
|
||||
Inst::Load(ty) => {
|
||||
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)
|
||||
}
|
||||
Inst::Store(ty) => {
|
||||
let ty = mir::Type::from_bytesize_int(ty.size());
|
||||
let (src, dst) = data.unwrap().as_lhs_rhs();
|
||||
let src = *mapping.get(&src).unwrap();
|
||||
let dst = *mapping.get(&dst).unwrap();
|
||||
let src = mapping.get(&mut mir, src).unwrap().0;
|
||||
let dst = mapping.get(&mut mir, dst).unwrap().0;
|
||||
mir.gen_store(ty, src, dst)
|
||||
}
|
||||
Inst::GetElementPtr(ty) => {
|
||||
let ty = mir::Type::from_bytesize_int(ty.size());
|
||||
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)
|
||||
}
|
||||
Inst::Parameter(ty) => {
|
||||
|
@ -1247,8 +1325,8 @@ impl<'a> MirBuilder<'a> {
|
|||
| Inst::Ge(ty)
|
||||
| Inst::Le(ty) => {
|
||||
let (src, dst) = data.unwrap().as_lhs_rhs();
|
||||
let lhs = *mapping.get(&src).unwrap();
|
||||
let rhs = *mapping.get(&dst).unwrap();
|
||||
let lhs = mapping.get(&mut mir, src).unwrap().0;
|
||||
let rhs = mapping.get(&mut mir, dst).unwrap().0;
|
||||
|
||||
#[cfg_attr(rustfmt, rustfmt::skip)]
|
||||
let (ord, invert)= match inst {
|
||||
|
@ -1265,8 +1343,8 @@ impl<'a> MirBuilder<'a> {
|
|||
}
|
||||
Inst::Add(ty) => {
|
||||
let (src, dst) = data.unwrap().as_lhs_rhs();
|
||||
let lhs = *mapping.get(&src).unwrap();
|
||||
let rhs = *mapping.get(&dst).unwrap();
|
||||
let lhs = mapping.get(&mut mir, src).unwrap().0;
|
||||
let rhs = mapping.get(&mut mir, dst).unwrap().0;
|
||||
|
||||
match ty {
|
||||
Type2::Integral(signed, bits) => match bits {
|
||||
|
@ -1292,8 +1370,8 @@ impl<'a> MirBuilder<'a> {
|
|||
}
|
||||
Inst::Sub(ty) => {
|
||||
let (src, dst) = data.unwrap().as_lhs_rhs();
|
||||
let lhs = *mapping.get(&src).unwrap();
|
||||
let rhs = *mapping.get(&dst).unwrap();
|
||||
let lhs = mapping.get(&mut mir, src).unwrap().0;
|
||||
let rhs = mapping.get(&mut mir, dst).unwrap().0;
|
||||
|
||||
let unalignment = ty.mir_unalignment();
|
||||
let ty = ty.mir_type();
|
||||
|
@ -1312,8 +1390,8 @@ impl<'a> MirBuilder<'a> {
|
|||
let signed = ty.is_signed();
|
||||
let ty = ty.mir_type();
|
||||
|
||||
let lhs = *mapping.get(&lhs).unwrap();
|
||||
let rhs = *mapping.get(&rhs).unwrap();
|
||||
let lhs = mapping.get(&mut mir, lhs).unwrap().0;
|
||||
let rhs = mapping.get(&mut mir, rhs).unwrap().0;
|
||||
|
||||
let sum = mir.gen_mul(ty, signed, lhs, rhs);
|
||||
if let Some((signed, bits)) = unalignment {
|
||||
|
@ -1329,8 +1407,8 @@ impl<'a> MirBuilder<'a> {
|
|||
let signed = ty.is_signed();
|
||||
let ty = ty.mir_type();
|
||||
|
||||
let lhs = *mapping.get(&lhs).unwrap();
|
||||
let rhs = *mapping.get(&rhs).unwrap();
|
||||
let lhs = mapping.get(&mut mir, lhs).unwrap().0;
|
||||
let rhs = mapping.get(&mut mir, rhs).unwrap().0;
|
||||
|
||||
let sum = mir.gen_div(ty, signed, lhs, rhs);
|
||||
if let Some((signed, bits)) = unalignment {
|
||||
|
@ -1346,8 +1424,8 @@ impl<'a> MirBuilder<'a> {
|
|||
let signed = ty.is_signed();
|
||||
let ty = ty.mir_type();
|
||||
|
||||
let lhs = *mapping.get(&lhs).unwrap();
|
||||
let rhs = *mapping.get(&rhs).unwrap();
|
||||
let lhs = mapping.get(&mut mir, lhs).unwrap().0;
|
||||
let rhs = mapping.get(&mut mir, rhs).unwrap().0;
|
||||
|
||||
let sum = mir.gen_rem(ty, signed, lhs, rhs);
|
||||
if let Some((signed, bits)) = unalignment {
|
||||
|
@ -1368,8 +1446,8 @@ impl<'a> MirBuilder<'a> {
|
|||
(lhs, rhs)
|
||||
};
|
||||
|
||||
let lhs = *mapping.get(&lhs).unwrap();
|
||||
let rhs = *mapping.get(&rhs).unwrap();
|
||||
let lhs = mapping.get(&mut mir, lhs).unwrap().0;
|
||||
let rhs = mapping.get(&mut mir, rhs).unwrap().0;
|
||||
|
||||
let sum = mir.gen_bitand(ty, lhs, rhs);
|
||||
if let Some((signed, bits)) = unalignment {
|
||||
|
@ -1390,8 +1468,8 @@ impl<'a> MirBuilder<'a> {
|
|||
(lhs, rhs)
|
||||
};
|
||||
|
||||
let lhs = *mapping.get(&lhs).unwrap();
|
||||
let rhs = *mapping.get(&rhs).unwrap();
|
||||
let lhs = mapping.get(&mut mir, lhs).unwrap().0;
|
||||
let rhs = mapping.get(&mut mir, rhs).unwrap().0;
|
||||
|
||||
let sum = mir.gen_bitor(ty, lhs, rhs);
|
||||
if let Some((signed, bits)) = unalignment {
|
||||
|
@ -1412,8 +1490,8 @@ impl<'a> MirBuilder<'a> {
|
|||
(lhs, rhs)
|
||||
};
|
||||
|
||||
let lhs = *mapping.get(&lhs).unwrap();
|
||||
let rhs = *mapping.get(&rhs).unwrap();
|
||||
let lhs = mapping.get(&mut mir, lhs).unwrap().0;
|
||||
let rhs = mapping.get(&mut mir, rhs).unwrap().0;
|
||||
|
||||
let sum = mir.gen_bitxor(ty, lhs, rhs);
|
||||
if let Some((signed, bits)) = unalignment {
|
||||
|
@ -1424,8 +1502,8 @@ impl<'a> MirBuilder<'a> {
|
|||
}
|
||||
Inst::ShiftLeft(ty) => {
|
||||
let (src, dst) = data.unwrap().as_lhs_rhs();
|
||||
let lhs = *mapping.get(&src).unwrap();
|
||||
let rhs = *mapping.get(&dst).unwrap();
|
||||
let lhs = mapping.get(&mut mir, src).unwrap().0;
|
||||
let rhs = mapping.get(&mut mir, dst).unwrap().0;
|
||||
|
||||
// TODO: check rhs type and pass it to gen_sh{l,r}?
|
||||
let rhs = mir.gen_truncate_integer(rhs, ty.into(), false, 8);
|
||||
|
@ -1450,8 +1528,8 @@ impl<'a> MirBuilder<'a> {
|
|||
}
|
||||
Inst::ShiftRight(ty) => {
|
||||
let (src, dst) = data.unwrap().as_lhs_rhs();
|
||||
let lhs = *mapping.get(&src).unwrap();
|
||||
let rhs = *mapping.get(&dst).unwrap();
|
||||
let lhs = mapping.get(&mut mir, src).unwrap().0;
|
||||
let rhs = mapping.get(&mut mir, dst).unwrap().0;
|
||||
|
||||
match ty {
|
||||
Type2::Integral(signed, bits) => match bits {
|
||||
|
@ -1487,7 +1565,7 @@ impl<'a> MirBuilder<'a> {
|
|||
let unalignment = ty.mir_unalignment();
|
||||
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);
|
||||
if let Some((signed, bits)) = unalignment {
|
||||
|
@ -1502,7 +1580,7 @@ impl<'a> MirBuilder<'a> {
|
|||
let unalignment = ty.mir_unalignment();
|
||||
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);
|
||||
if let Some((signed, bits)) = unalignment {
|
||||
|
@ -1516,7 +1594,7 @@ impl<'a> MirBuilder<'a> {
|
|||
let from_mir = from.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) {
|
||||
(Type2::Integral(a_signed, a), Type2::Integral(b_signed, b)) => {
|
||||
|
@ -1546,7 +1624,7 @@ impl<'a> MirBuilder<'a> {
|
|||
}
|
||||
Inst::ReturnValue(ty) => {
|
||||
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)
|
||||
}
|
||||
|
@ -1556,8 +1634,8 @@ impl<'a> MirBuilder<'a> {
|
|||
|
||||
let jmp = mir.gen_jmp(label);
|
||||
|
||||
let label = match mapping.get(&label) {
|
||||
Some(&label) => label,
|
||||
let label = match mapping.get(&mut mir, label) {
|
||||
Some(label) => label.0,
|
||||
None => {
|
||||
unresolved_jumps_branches
|
||||
.insert((label, LeftRight::Left(mir::NodeRef(jmp))));
|
||||
|
@ -1570,21 +1648,21 @@ impl<'a> MirBuilder<'a> {
|
|||
jmp
|
||||
}
|
||||
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 br = mir.gen_branch(condition, lhs, rhs);
|
||||
|
||||
let lhs = match mapping.get(&lhs) {
|
||||
Some(&n) => n,
|
||||
let lhs = match mapping.get(&mut mir, lhs) {
|
||||
Some(n) => n.0,
|
||||
None => {
|
||||
unresolved_jumps_branches
|
||||
.insert((lhs, LeftRight::Left(mir::NodeRef(br))));
|
||||
0
|
||||
}
|
||||
};
|
||||
let rhs = match mapping.get(&rhs) {
|
||||
Some(&n) => n,
|
||||
let rhs = match mapping.get(&mut mir, rhs) {
|
||||
Some(n) => n.0,
|
||||
None => {
|
||||
unresolved_jumps_branches
|
||||
.insert((rhs, LeftRight::Right(mir::NodeRef(br))));
|
||||
|
@ -1598,18 +1676,24 @@ impl<'a> MirBuilder<'a> {
|
|||
}
|
||||
Inst::Phi2(ty) => {
|
||||
let (src, dst) = data.unwrap().as_lhs_rhs();
|
||||
let lhs = *mapping.get(&src).unwrap();
|
||||
let rhs = *mapping.get(&dst).unwrap();
|
||||
let lhs = mapping.get(&mut mir, src).unwrap().0;
|
||||
let rhs = mapping.get(&mut mir, dst).unwrap().0;
|
||||
|
||||
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)]
|
||||
_ => {
|
||||
eprintln!("ir inst {inst:?} not supported in mir translation");
|
||||
unimplemented!()
|
||||
}
|
||||
};
|
||||
|
||||
mapping.insert(ir_node, node);
|
||||
mapping.insert(ir_node, mir::NodeRef(node));
|
||||
}
|
||||
|
||||
self.functions.insert(name, mir);
|
||||
|
@ -1622,6 +1706,50 @@ impl<'a> MirBuilder<'a> {
|
|||
};
|
||||
match inst {
|
||||
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::*;
|
||||
|
||||
#[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]
|
||||
fn mir_u10() {
|
||||
let src = "
|
||||
|
|
Loading…
Reference in a new issue