global symbols
This commit is contained in:
parent
4b432f404b
commit
4424ef875d
|
@ -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}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
227
src/mir.rs
227
src/mir.rs
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
311
src/triples.rs
311
src/triples.rs
|
@ -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 = "
|
||||||
|
|
Loading…
Reference in a new issue