Skip to content

Commit

Permalink
WIP: better generics
Browse files Browse the repository at this point in the history
  • Loading branch information
yorickpeterse committed Sep 5, 2023
1 parent 97c7fb3 commit 822a428
Show file tree
Hide file tree
Showing 14 changed files with 1,386 additions and 143 deletions.
17 changes: 10 additions & 7 deletions compiler/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ use crate::config::{Config, SOURCE, SOURCE_EXT, TESTS};
use crate::hir;
use crate::linker::link;
use crate::llvm;
use crate::mir::passes as mir;
use crate::mir::printer::to_dot;
use crate::mir::{passes as mir, Mir};
use crate::mir::specialize::Specialize;
use crate::mir::Mir;
use crate::modules_parser::{ModulesParser, ParsedModule};
use crate::state::State;
use crate::type_check::define_types::{
Expand Down Expand Up @@ -131,12 +133,12 @@ impl Compiler {
}

let mut mir = Mir::new();
let state = &mut self.state;

mir::check_global_limits(&mut self.state)
.map_err(CompileError::Internal)?;
mir::check_global_limits(state).map_err(CompileError::Internal)?;

if mir::DefineConstants::run_all(&mut self.state, &mut mir, &modules)
&& mir::LowerToMir::run_all(&mut self.state, &mut mir, modules)
if mir::DefineConstants::run_all(state, &mut mir, &modules)
&& mir::LowerToMir::run_all(state, &mut mir, modules)
{
Ok(mir)
} else {
Expand Down Expand Up @@ -185,8 +187,9 @@ impl Compiler {
}

fn optimise_mir(&mut self, mir: &mut Mir) {
mir::ExpandDrop::run_all(&self.state.db, mir);
mir::ExpandReference::run_all(&self.state.db, mir);
Specialize::run_all(&mut self.state, mir);
mir::ExpandDrop::run_all(&self.state.db, mir); // TODO: remove in favour of specialization
mir::ExpandReference::run_all(&self.state.db, mir); // TODO: remove in favour of specialization
mir::clean_up_basic_blocks(mir);
}

Expand Down
8 changes: 4 additions & 4 deletions compiler/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ pub(crate) struct DefineVariant {
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct AssignInstanceLiteralField {
pub(crate) struct AssignClassLiteralField {
pub(crate) resolved_type: types::TypeRef,
pub(crate) field_id: Option<types::FieldId>,
pub(crate) field: Field,
Expand All @@ -349,7 +349,7 @@ pub(crate) struct ClassLiteral {
pub(crate) class_id: Option<types::ClassId>,
pub(crate) resolved_type: types::TypeRef,
pub(crate) class_name: Constant,
pub(crate) fields: Vec<AssignInstanceLiteralField>,
pub(crate) fields: Vec<AssignClassLiteralField>,
pub(crate) location: SourceLocation,
}

Expand Down Expand Up @@ -2794,7 +2794,7 @@ impl<'a> LowerToHir<'a> {
fields: node
.fields
.into_iter()
.map(|n| AssignInstanceLiteralField {
.map(|n| AssignClassLiteralField {
resolved_type: types::TypeRef::Unknown,
field_id: None,
field: self.field(n.field),
Expand Down Expand Up @@ -5923,7 +5923,7 @@ mod tests {
name: "A".to_string(),
location: cols(8, 8)
},
fields: vec![AssignInstanceLiteralField {
fields: vec![AssignClassLiteralField {
resolved_type: types::TypeRef::Unknown,
field_id: None,
field: Field {
Expand Down
15 changes: 8 additions & 7 deletions compiler/src/llvm/layouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use inkwell::AddressSpace;
use std::cmp::max;
use std::collections::HashMap;
use types::{
ClassId, MethodId, MethodSource, BOOLEAN_ID, BYTE_ARRAY_ID, CALL_METHOD,
CHANNEL_ID, DROPPER_METHOD, FLOAT_ID, INT_ID, NIL_ID,
ClassId, MethodId, MethodSource, TraitId, BOOL_ID, BYTE_ARRAY_ID,
CALL_METHOD, CHANNEL_ID, DROPPER_METHOD, FLOAT_ID, INT_ID, NIL_ID,
};

/// The size of an object header.
Expand Down Expand Up @@ -180,12 +180,13 @@ impl<'ctx> Layouts<'ctx> {
//
// This information is defined first so we can update the `collision`
// flag when generating this information for method implementations.
for mir_trait in mir.traits.values() {
for method in mir_trait
.id
for idx in 0..db.number_of_traits() {
let id = TraitId(idx as _);

for method in id
.required_methods(db)
.into_iter()
.chain(mir_trait.id.default_methods(db))
.chain(id.default_methods(db))
{
let name = method.name(db);
let hash = method_hasher.hash(name);
Expand Down Expand Up @@ -249,7 +250,7 @@ impl<'ctx> Layouts<'ctx> {
header,
context.f64_type().into(),
),
BOOLEAN_ID | NIL_ID => {
BOOL_ID | NIL_ID => {
let typ = context.opaque_struct(&name);

typ.set_body(&[header.into()], false);
Expand Down
102 changes: 76 additions & 26 deletions compiler/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@
//!
//! MIR is used for various optimisations, analysing moves of values, compiling
//! pattern matching into decision trees, and more.
use crate::symbol_names::class_name;
use ast::source_location::SourceLocation;
use std::collections::{HashMap, HashSet};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use types::collections::IndexMap;
use types::{BuiltinFunction, Database};
use types::{BuiltinFunction, Database, TypeArguments};

/// The number of reductions to perform after calling a method.
const CALL_COST: u16 = 1;

pub(crate) mod passes;
pub(crate) mod pattern_matching;
pub(crate) mod printer;
pub(crate) mod specialize;

fn join(values: &[RegisterId]) -> String {
values.iter().map(|v| format!("r{}", v.0)).collect::<Vec<_>>().join(", ")
Expand All @@ -42,13 +44,21 @@ impl Registers {
&self.values[register.0 as usize]
}

pub(crate) fn get_mut(&mut self, register: RegisterId) -> &mut Register {
&mut self.values[register.0 as usize]
}

pub(crate) fn value_type(&self, register: RegisterId) -> types::TypeRef {
self.get(register).value_type
}

pub(crate) fn len(&self) -> usize {
self.values.len()
}

pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = &mut Register> {
self.values.iter_mut()
}
}

/// A directed control-flow graph.
Expand Down Expand Up @@ -409,12 +419,14 @@ impl Block {
register: RegisterId,
method: types::MethodId,
arguments: Vec<RegisterId>,
type_arguments: Option<usize>,
location: LocationId,
) {
self.instructions.push(Instruction::CallStatic(Box::new(CallStatic {
register,
method,
arguments,
type_arguments,
location,
})));
}
Expand All @@ -425,10 +437,18 @@ impl Block {
receiver: RegisterId,
method: types::MethodId,
arguments: Vec<RegisterId>,
type_arguments: Option<usize>,
location: LocationId,
) {
self.instructions.push(Instruction::CallInstance(Box::new(
CallInstance { register, receiver, method, arguments, location },
CallInstance {
register,
receiver,
method,
arguments,
type_arguments,
location,
},
)));
}

Expand All @@ -453,10 +473,18 @@ impl Block {
receiver: RegisterId,
method: types::MethodId,
arguments: Vec<RegisterId>,
type_arguments: Option<usize>,
location: LocationId,
) {
self.instructions.push(Instruction::CallDynamic(Box::new(
CallDynamic { register, receiver, method, arguments, location },
CallDynamic {
register,
receiver,
method,
arguments,
type_arguments,
location,
},
)));
}

Expand Down Expand Up @@ -500,12 +528,14 @@ impl Block {
receiver: RegisterId,
method: types::MethodId,
arguments: Vec<RegisterId>,
type_arguments: Option<usize>,
location: LocationId,
) {
self.instructions.push(Instruction::Send(Box::new(Send {
receiver,
method,
arguments,
type_arguments,
location,
})));
}
Expand Down Expand Up @@ -740,6 +770,7 @@ pub(crate) struct Switch {
pub(crate) location: LocationId,
}

// TODO: remove after implementing specialization
#[derive(Clone)]
pub(crate) struct SwitchKind {
pub(crate) register: RegisterId,
Expand Down Expand Up @@ -893,6 +924,7 @@ pub(crate) struct CallStatic {
pub(crate) register: RegisterId,
pub(crate) method: types::MethodId,
pub(crate) arguments: Vec<RegisterId>,
pub(crate) type_arguments: Option<usize>,
pub(crate) location: LocationId,
}

Expand All @@ -902,6 +934,7 @@ pub(crate) struct CallInstance {
pub(crate) receiver: RegisterId,
pub(crate) method: types::MethodId,
pub(crate) arguments: Vec<RegisterId>,
pub(crate) type_arguments: Option<usize>,
pub(crate) location: LocationId,
}

Expand All @@ -919,6 +952,7 @@ pub(crate) struct CallDynamic {
pub(crate) receiver: RegisterId,
pub(crate) method: types::MethodId,
pub(crate) arguments: Vec<RegisterId>,
pub(crate) type_arguments: Option<usize>,
pub(crate) location: LocationId,
}

Expand All @@ -943,6 +977,7 @@ pub(crate) struct Send {
pub(crate) receiver: RegisterId,
pub(crate) method: types::MethodId,
pub(crate) arguments: Vec<RegisterId>,
pub(crate) type_arguments: Option<usize>,
pub(crate) location: LocationId,
}

Expand Down Expand Up @@ -1219,15 +1254,27 @@ impl Instruction {
format!("return r{}", v.register.0)
}
Instruction::Allocate(ref v) => {
format!("r{} = allocate {}", v.register.0, v.class.name(db))
format!(
"r{} = allocate {}",
v.register.0,
class_name(db, v.class),
)
}
Instruction::Spawn(ref v) => {
format!("r{} = spawn {}", v.register.0, v.class.name(db))
}
Instruction::CallStatic(ref v) => {
let class = v
.method
.receiver(db)
.as_class(db)
.map(|v| v.name(db))
.expect("static methods must have a valid receiver");

format!(
"r{} = call_static {}({})",
"r{} = call_static {}.{}({})",
v.register.0,
class,
v.method.name(db),
join(&v.arguments)
)
Expand Down Expand Up @@ -1376,33 +1423,17 @@ impl Class {
}
}

pub(crate) struct Trait {
pub(crate) id: types::TraitId,
pub(crate) methods: Vec<types::MethodId>,
}

impl Trait {
pub(crate) fn new(id: types::TraitId) -> Self {
Self { id, methods: Vec::new() }
}

pub(crate) fn add_methods(&mut self, methods: &Vec<Method>) {
for method in methods {
self.methods.push(method.id);
}
}
}

#[derive(Clone)]
pub(crate) struct Module {
pub(crate) id: types::ModuleId,
pub(crate) classes: Vec<types::ClassId>,
pub(crate) constants: Vec<types::ConstantId>,
pub(crate) location: LocationId,
}

impl Module {
pub(crate) fn new(id: types::ModuleId) -> Self {
Self { id, classes: Vec::new(), constants: Vec::new() }
pub(crate) fn new(id: types::ModuleId, location: LocationId) -> Self {
Self { id, classes: Vec::new(), constants: Vec::new(), location }
}
}

Expand Down Expand Up @@ -1435,8 +1466,15 @@ pub(crate) struct Mir {
pub(crate) constants: HashMap<types::ConstantId, Constant>,
pub(crate) modules: IndexMap<types::ModuleId, Module>,
pub(crate) classes: HashMap<types::ClassId, Class>,
pub(crate) traits: HashMap<types::TraitId, Trait>,
pub(crate) methods: HashMap<types::MethodId, Method>,

/// The type arguments to expose to call instructions, used to specialize
/// types and method calls.
///
/// This data is stored out of bounds and addressed through an index, as
/// it's only needed by the specialization pass, and this makes it easy to
/// remove the data once we no longer need it.
pub(crate) type_arguments: Vec<TypeArguments>,
locations: Vec<SourceLocation>,
}

Expand All @@ -1446,8 +1484,8 @@ impl Mir {
constants: HashMap::new(),
modules: IndexMap::new(),
classes: HashMap::new(),
traits: HashMap::new(),
methods: HashMap::new(),
type_arguments: Vec::new(),
locations: Vec::new(),
}
}
Expand All @@ -1458,6 +1496,18 @@ impl Mir {
}
}

pub(crate) fn add_type_arguments(
&mut self,
arguments: TypeArguments,
) -> Option<usize> {
if arguments.is_empty() {
None
} else {
self.type_arguments.push(arguments);
Some(self.type_arguments.len() - 1)
}
}

pub(crate) fn add_location(
&mut self,
location: SourceLocation,
Expand Down
Loading

0 comments on commit 822a428

Please sign in to comment.