Skip to content

Commit

Permalink
Merge pull request #12 from binary-banter/new_type_checking
Browse files Browse the repository at this point in the history
New type checking
  • Loading branch information
JonathanBrouwer authored Nov 25, 2023
2 parents 029f936 + 1f3fd01 commit 6a4fe77
Show file tree
Hide file tree
Showing 335 changed files with 5,556 additions and 4,489 deletions.
380 changes: 266 additions & 114 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@ cargo run -- input.jj -o output && ./output ; echo $?
# Fixes
* [ ] Updated README, with 3 new colors!
* [ ] Add documentation where necessary.
* [ ] Improve error handling for parsing pass.
* [ ] Improve error handling for type checking pass.
* [x] Improve error handling for parsing pass.
* [x] Improve error handling for type checking pass.
* [ ] Make errors prettier.
* [ ] Improve algorithm for colouring the interference graph.
* [ ] Add read and write functionality to the bencher to update locally.
* [x] Lots, and lots, of refactoring!
* [x] Write test input in comments.

# Upcoming Language Features
* [x] Type inference.
* [x] Implement comments in code.
* [ ] Algebraic Data Types.
* [x] Structs.
Expand Down
12 changes: 5 additions & 7 deletions bencher/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use clap::Parser;
use compiler::interpreter::TestIO;
use compiler::passes::parse::parse::parse_program;
use compiler::passes::select::interpreter::IStats;
use compiler::utils::split_test::split_test;
use git2::{Commit, Repository};
Expand Down Expand Up @@ -263,25 +264,22 @@ fn write_commit(benches: &Collection<Document>, commit: &Commit<'_>, test_data:

impl Stats {
fn from_program(program: &str) -> Self {
let (input, _, _, program) = split_test(program);
let (input, _, _, _) = split_test(program);
let mut io = TestIO::new(input);

let tempdir = TempDir::new("cc-bench").unwrap();
let output = tempdir.path().join("output");

let prg_concluded = program
let prg_concluded = parse_program(program)
.unwrap()
.validate()
.unwrap()
.uniquify()
.reveal()
.atomize()
.explicate()
.eliminate()
.select()
.add_liveness()
.compute_interference()
.color_interference()
.assign_homes()
.assign()
.patch()
.conclude();

Expand Down
6 changes: 5 additions & 1 deletion compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ zerocopy = { version = "0.7.25", features = ["derive"] }
lalrpop-util = { version = "0.20.0", features = ["lexer", "unicode"] }
derive_more = "0.99.17"
functor_derive = "0.2.3"
indenter = "0.3.3"
once_cell = "1.18.0"

[build-dependencies]
lalrpop = "0.20.0"

[dev-dependencies]
test_each_file = "0.1.1"
test_each_file = "0.2.0"
tempfile = "3.8.1"
enum-display = "0.1.3"
derive-name = "1.1.0"
25 changes: 13 additions & 12 deletions compiler/src/interpreter.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::passes::validate::TLit;
use crate::utils::gen_sym::UniqueSym;
use derive_more::Display;
use std::collections::HashMap;
use std::fmt::Display;
use std::hash::Hash;

use std::vec::IntoIter;

pub trait IO {
Expand Down Expand Up @@ -41,32 +41,33 @@ impl IO for TestIO {
}

#[derive(Eq, PartialEq, Clone, Debug, Display)]
pub enum Val<'p, A: Copy + Hash + Eq + Display> {
pub enum Val<'p> {
#[display(fmt = "{val}")]
Int { val: i64 },
#[display(fmt = "{}", r#"if *val { "true" } else { "false" }"#)]
Bool { val: bool },
#[display(fmt = "unit")]
Unit,
#[display(fmt = "fn pointer `{sym}`")]
Function { sym: A },
Function { sym: UniqueSym<'p> },
#[display(fmt = "stdlib function `{sym}`")]
StdlibFunction { sym: &'p str },
#[display(fmt = "struct instance")]
StructInstance {
fields: HashMap<&'p str, Val<'p, A>>,
},
StructInstance { fields: HashMap<&'p str, Val<'p>> },
}

impl<'p, A: Copy + Hash + Eq + Display> From<TLit> for Val<'p, A> {
impl<'p> From<TLit> for Val<'p> {
fn from(value: TLit) -> Self {
match value {
TLit::Int { val } => Val::Int { val: val as i64 },
TLit::I64 { val } => Val::Int { val },
TLit::U64 { val } => Val::Int { val: val as i64 },
TLit::Bool { val } => Val::Bool { val },
TLit::Unit => Val::Unit,
}
}
}

impl<'p, A: Copy + Hash + Eq + Display> Val<'p, A> {
impl<'p> Val<'p> {
pub fn int(&self) -> i64 {
match self {
Val::Int { val } => *val,
Expand All @@ -81,14 +82,14 @@ impl<'p, A: Copy + Hash + Eq + Display> Val<'p, A> {
}
}

pub fn fun(&self) -> A {
pub fn fun(&self) -> UniqueSym<'p> {
match self {
Val::Function { sym } => *sym,
_ => panic!(),
}
}

pub fn strct(&self) -> &HashMap<&'p str, Val<'p, A>> {
pub fn strct(&self) -> &HashMap<&'p str, Val<'p>> {
match self {
Val::StructInstance { fields } => fields,
_ => panic!(),
Expand Down
6 changes: 1 addition & 5 deletions compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,12 @@ pub fn compile(program: &str, filename: &str, output: &Path) -> miette::Result<(
.validate()
.map_err(Into::into)
.map_err(add_source)?
.uniquify()
.reveal()
.atomize()
.explicate()
.eliminate()
.select()
.add_liveness()
.compute_interference()
.color_interference()
.assign_homes()
.assign()
.patch()
.conclude()
.emit()
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use clap::Parser;
use compiler::compile;
use compiler::passes::parse::parse::PrettyParseError;
use compiler::passes::validate::ValidateError;
use compiler::passes::validate::error::TypeError;
use miette::{Diagnostic, IntoDiagnostic};
use std::fs;
use std::io::Read;
Expand All @@ -15,7 +15,7 @@ enum MainError {
ParseError(#[from] PrettyParseError),
#[error(transparent)]
#[diagnostic(transparent)]
ValidateError(#[from] ValidateError),
ValidateError(#[from] TypeError),
}

#[derive(Parser, Debug)]
Expand Down
78 changes: 78 additions & 0 deletions compiler/src/passes/assign/assign.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use crate::passes::assign::{Arg, X86Assigned};
use crate::passes::select::{Block, Instr, VarArg, X86Selected};
use crate::utils::gen_sym::UniqueSym;
use crate::*;
use std::collections::HashMap;

impl<'p> X86Selected<'p> {
#[must_use]
pub fn assign(self) -> X86Assigned<'p> {
let program = self.include_liveness();
let interference = program.compute_interference();
let (color_map, stack_space) = interference.color();

let blocks = program
.blocks
.into_iter()
.map(|(lbl, block)| (lbl, assign_block(block.into(), &color_map)))
.collect();

X86Assigned {
blocks,
entry: program.entry,
stack_space,
std: program.std,
}
}
}

fn assign_block<'p>(
block: Block<'p, VarArg>,
color_map: &HashMap<UniqueSym, Arg>,
) -> Block<'p, Arg> {
Block {
instrs: block
.instrs
.into_iter()
.map(|instr| assign_instr(instr, color_map))
.collect(),
}
}

fn assign_instr<'p>(
instr: Instr<'p, VarArg>,
color_map: &HashMap<UniqueSym, Arg>,
) -> Instr<'p, Arg> {
let map = |arg: VarArg| -> Arg {
match arg {
VarArg::Imm { val } => Arg::Imm { val },
VarArg::Reg { reg } => Arg::Reg { reg },
VarArg::Deref { reg, off } => Arg::Deref { reg, off },
VarArg::XVar { sym } => color_map[&sym].clone(),
}
};

match instr {
Instr::Addq { src, dst } => addq!(map(src), map(dst)),
Instr::Subq { src, dst } => subq!(map(src), map(dst)),
Instr::Divq { divisor } => divq!(map(divisor)),
Instr::Mulq { src } => mulq!(map(src)),
Instr::Negq { dst } => negq!(map(dst)),
Instr::Movq { src, dst } => movq!(map(src), map(dst)),
Instr::Pushq { src } => pushq!(map(src)),
Instr::Popq { dst } => popq!(map(dst)),
Instr::CallqDirect { lbl, arity } => callq_direct!(lbl, arity),
Instr::Retq => retq!(),
Instr::Syscall { arity } => syscall!(arity),
Instr::Jmp { lbl } => jmp!(lbl),
Instr::Jcc { lbl, cnd } => jcc!(lbl, cnd),
Instr::Cmpq { src, dst } => cmpq!(map(src), map(dst)),
Instr::Andq { src, dst } => andq!(map(src), map(dst)),
Instr::Orq { src, dst } => orq!(map(src), map(dst)),
Instr::Xorq { src, dst } => xorq!(map(src), map(dst)),
Instr::Notq { dst } => notq!(map(dst)),
Instr::Setcc { cnd } => setcc!(cnd),
Instr::LoadLbl { sym, dst } => load_lbl!(sym, map(dst)),
Instr::CallqIndirect { src, arity } => callq_indirect!(map(src), arity),
}
}
114 changes: 114 additions & 0 deletions compiler/src/passes/assign/color_interference.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use crate::passes::assign::{Arg, InterferenceGraph, LArg};
use crate::passes::select::Reg;
use crate::utils::gen_sym::UniqueSym;
use itertools::Itertools;
use std::collections::{HashMap, HashSet};

impl<'p> InterferenceGraph<'p> {
#[must_use]
pub fn color(self) -> (HashMap<UniqueSym<'p>, Arg>, usize) {
let graph = self.0;
let mut queue = Vec::new();
let mut node_map = HashMap::<LArg, isize>::new();

for node in graph.nodes() {
match node {
LArg::Var { .. } => {
queue.push(node);
}
LArg::Reg { reg } => {
let node_weight = match reg {
Reg::RCX => 0,
Reg::RDX => 1,
Reg::RSI => 2,
Reg::RDI => 3,
Reg::R8 => 4,
Reg::R9 => 5,
Reg::R10 => 6,
Reg::RBX => 7,
Reg::R12 => 8,
Reg::R13 => 9,
Reg::R14 => 10,
Reg::RAX => -1,
Reg::RSP => -2,
Reg::RBP => -3,
Reg::R11 => -4,
Reg::R15 => -5,
};
node_map.insert(node, node_weight);
}
}
}

while let Some(node) = queue.pop() {
let used_colors = graph
.neighbors(node)
.filter_map(|nb| node_map.get(&nb))
.collect::<HashSet<_>>();

let chosen_color = (0..)
.find(|i| !used_colors.contains(i))
.expect("there are infinite numbers, lol");

node_map.insert(node, chosen_color);

queue.sort_by_key(|node| {
graph
.neighbors(*node)
.filter_map(|nb| node_map.get(&nb))
.unique()
.count()
});
}

let used_vars = node_map
.values()
.filter(|&&n| n >= 10)
.map(|&n| n - 10)
.max()
.unwrap_or_default() as usize;

let stack_space = (8 * used_vars).div_ceil(16) * 16;

let colors = node_map
.into_iter()
.filter_map(|(node, color)| match node {
LArg::Var { sym } => Some((sym, arg_from_color(color))),
LArg::Reg { .. } => None,
})
.collect();

(colors, stack_space)
}
}

fn arg_from_color(i: isize) -> Arg {
match i {
-5 => Arg::Reg { reg: Reg::R15 },
-4 => Arg::Reg { reg: Reg::R11 },
-3 => Arg::Reg { reg: Reg::RBP },
-2 => Arg::Reg { reg: Reg::RSP },
-1 => Arg::Reg { reg: Reg::RAX },
0 => Arg::Reg { reg: Reg::RCX },
1 => Arg::Reg { reg: Reg::RDX },
2 => Arg::Reg { reg: Reg::RSI },
3 => Arg::Reg { reg: Reg::RDI },
4 => Arg::Reg { reg: Reg::R8 },
5 => Arg::Reg { reg: Reg::R9 },
6 => Arg::Reg { reg: Reg::R10 },
7 => Arg::Reg { reg: Reg::RBX },
8 => Arg::Reg { reg: Reg::R12 },
9 => Arg::Reg { reg: Reg::R13 },
10 => Arg::Reg { reg: Reg::R14 },
i => {
assert!(
i > 10,
"Something went wrong while coloring the assign graph."
);
Arg::Deref {
reg: Reg::RBP,
off: (-8 * (i - 10)) as i64,
}
}
}
}
Loading

0 comments on commit 6a4fe77

Please sign in to comment.