Skip to content

Commit

Permalink
make it easier to add new builtins
Browse files Browse the repository at this point in the history
  • Loading branch information
simvux committed Oct 9, 2024
1 parent 16fb5c0 commit 6b31023
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 153 deletions.
136 changes: 136 additions & 0 deletions lumina-compiler/src/mir/builtins.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
use crate::{hir, mir, mir::Expr};
use lumina_typesystem::{Container, Transformer, Ty, Var};
use lumina_util::{Span, Spanned, Tr};
use mir::func::InstCall;
use std::collections::HashMap;

pub fn signature<'t, 's>(lower: &mut mir::Verify<'t, 's>, span: Span, name: &str) -> InstCall {
macro_rules! sig {
($($param:tt),* => $ret:tt) => {
{
let ptypes = [$(ty!($param)),*].into();
let ret = ty!($ret);
InstCall::LocalCall(span, ptypes, ret, Container::FnPointer)
}
};
(direct $param:tt) => {
{
let param = ty!($param);
InstCall::Local(param.tr(span))
}
}
}

let mut generics: HashMap<char, Var> = HashMap::new();

macro_rules! ty {
(bool) => { Ty::bool() };
(uint) => { Ty::Int(lower.target.uint()) };
((pointer $inner:tt)) => { Ty::pointer(ty!($inner)) };
(($($param:tt),*)) => { Ty::tuple(vec![$(ty!($param)),*]) };
($generic:literal) => {
Ty::Special(
*generics
.entry($generic)
.or_insert_with(|| lower.vars().var(span)),
)
};
}

match name {
"plus" | "minus" | "mul" | "div" => {
sig! { 'a', 'a' => 'a' }
}
"plus_checked" | "minus_checked" | "mul_checked" | "div_checked" => {
sig! { 'a', 'a' => ('a', bool) }
}

"array_len" => sig! { 'a' => uint },
"array_get" => sig! { uint, 'a' => 'b' },
"iabs" => sig! { 'n' => 'n' },
"eq" | "lt" | "gt" => sig! { 'a', 'a' => bool },
"deref" => sig! { (pointer 'a') => 'a' },

"write" => sig! { (pointer 'a'), 'a' => () },
"offset" => sig! { (pointer 'a'), uint => (pointer 'a') },
"reflect_type" => {
InstCall::Local(Ty::defined(lower.items.pinfo.reflect_type, vec![]).tr(span))
}
"size_of" => sig! { direct uint },
"alloca" => sig! { direct (pointer 'a') },
"unreachable" => sig! { direct 'a' },
"transmute" => sig! { 'a' => 'b' },
"val_to_ref" => sig! { 'a' => (pointer 'a') },
_ => {
lower.error("unrecognised builtin").eline(span, "").emit();
InstCall::Local(Ty::poison().tr(span))
}
}
}

pub fn lower<'t, 's>(
lower: &mut mir::Lower<'t, 's>,
name: &str,
params: &[Tr<hir::Expr<'s>>],
tanot: &hir::TypeAnnotation<'s>,
) -> Expr {
match name {
"plus" => lower.lower_builtin(params, |p| Expr::Num("plus", Box::new(p))),
"minus" => lower.lower_builtin(params, |p| Expr::Num("minus", Box::new(p))),
"mul" => lower.lower_builtin(params, |p| Expr::Num("mul", Box::new(p))),
"div" => lower.lower_builtin(params, |p| Expr::Num("div", Box::new(p))),
"plus_checked" => lower.lower_builtin(params, |p| Expr::Num("plus_checked", Box::new(p))),
"minus_checked" => lower.lower_builtin(params, |p| Expr::Num("minus_checked", Box::new(p))),
"mul_checked" => lower.lower_builtin(params, |p| Expr::Num("mul_checked", Box::new(p))),
"div_checked" => lower.lower_builtin(params, |p| Expr::Num("div_checked", Box::new(p))),
"array_len" => lower.lower_builtin(params, |[p]| Expr::ArrayLen(Box::new(p))),
"array_get" => lower.lower_builtin(params, |p| Expr::ArrayAccess(Box::new(p))),
"iabs" => lower.lower_builtin(params, |[p]| Expr::IntAbs(Box::new(p))),
"eq" => lower.lower_builtin(params, |p| Expr::Cmp("eq", Box::new(p))),
"lt" => lower.lower_builtin(params, |p| Expr::Cmp("lt", Box::new(p))),
"gt" => lower.lower_builtin(params, |p| Expr::Cmp("gt", Box::new(p))),
"deref" => lower.lower_builtin(params, |[inner]| Expr::Deref(Box::new(inner))),
"write" => lower.lower_builtin(params, |p| Expr::Write(Box::new(p))),
"offset" => lower.lower_builtin(params, |p| Expr::Num("plus", Box::new(p))),
"unreachable" => {
let (name, ty) = tanot.for_entity[0].clone();
assert_eq!(*name, "self");
let ty = lower.finalizer().transform(&ty);
lower.lower_builtin::<0>(params, |_| Expr::Unreachable(ty))
}
"transmute" => lower.lower_builtin(params, |[inner]| inner),
"val_to_ref" => lower.lower_builtin(params, |[inner]| Expr::ValToRef(Box::new(inner))),
"reflect_type" => {
let (name, ty) = tanot.for_entity[0].clone();
assert_eq!(*name, "self");
let ty = lower.finalizer().transform(&ty);
Expr::ReflectTypeOf(ty)
}
"size_of" => {
let (name, ty) = tanot.for_entity[0].clone();
assert_eq!(*name, "self");
let ty = lower.finalizer().transform(&ty);
Expr::SizeOf(ty)
}
"alloca" => {
let (name, ty) = tanot.for_entity[0].clone();
assert_eq!(*name, "self");
let ty = lower.finalizer().transform(&ty);
Expr::Alloca(ty)
}
_ => panic!("unknown builtin: {name}"),
}
}

impl<'t, 's> mir::Lower<'t, 's> {
fn lower_builtin<const N: usize>(
&mut self,
params: &[Tr<hir::Expr<'s>>],
constructor: impl FnOnce([Expr; N]) -> Expr,
) -> Expr {
match <[Expr; N]>::try_from(self.lower_exprs(params)) {
Ok(params) => constructor(params),
Err(_) => Expr::Poison,
}
}
}
84 changes: 2 additions & 82 deletions lumina-compiler/src/mir/func.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{lower, tyfmt::TyFmtState, Current, LangItems, ReadOnlyBytes, Verify};
use super::{builtins, lower, tyfmt::TyFmtState, Current, LangItems, ReadOnlyBytes, Verify};
use crate::prelude::*;
use crate::{ProjectInfo, Target};
use ast::NFunc;
Expand Down Expand Up @@ -681,87 +681,7 @@ impl<'a, 's> Verify<'a, 's> {
}
}
}
hir::Callable::Builtin(name) => match *name {
"plus" | "minus" | "mul" | "div" => {
let any = Ty::infer(self.vars().var(span));
let ptypes = vec![any.clone(), any.clone()];
InstCall::LocalCall(span, ptypes, any, Container::FnPointer)
}
"plus_checked" | "minus_checked" | "mul_checked" | "div_checked" => {
let any = Ty::infer(self.vars().var(span));
let ptypes = vec![any.clone(), any.clone()];
let ret = Ty::tuple(vec![any, Ty::bool()]);
InstCall::LocalCall(span, ptypes, ret, Container::FnPointer)
}
"array_len" => {
let any = Ty::infer(self.vars().var(span));
let ptypes = vec![any];
let ret = Ty::Int(self.target.uint());
InstCall::LocalCall(span, ptypes, ret, Container::FnPointer)
}
"array_get" => {
let [arr, any] = [(); 2].map(|_| self.vars().var(span)).map(Ty::infer);
let ptypes = vec![Ty::Int(self.target.uint()), arr];
InstCall::LocalCall(span, ptypes, any, Container::FnPointer)
}
"iabs" => {
let any = Ty::infer(self.vars().var(span));
let ptypes = vec![any.clone()];
InstCall::LocalCall(span, ptypes, any, Container::FnPointer)
}
"eq" | "lt" | "gt" => {
let any = Ty::infer(self.vars().var(span));
let ptypes = vec![any.clone(), any];
InstCall::LocalCall(span, ptypes, Ty::bool(), Container::FnPointer)
}
"deref" => {
let any = Ty::infer(self.vars().var(span));
let ptypes = vec![Ty::pointer(any.clone())];
InstCall::LocalCall(span, ptypes, any, Container::FnPointer)
}
"write" => {
let any = Ty::infer(self.vars().var(span));
let ptypes = vec![Ty::pointer(any.clone()), any.clone()];
let ret = Ty::tuple(vec![]);
InstCall::LocalCall(span, ptypes, ret, Container::FnPointer)
}
"offset" => {
let any = Ty::infer(self.vars().var(span));
let ptr = Ty::pointer(any.clone());
let ptypes = vec![ptr.clone(), Ty::Int(self.target.int())];
InstCall::LocalCall(span, ptypes, ptr, Container::FnPointer)
}
"reflect_type" => {
InstCall::Local(Ty::defined(self.items.pinfo.reflect_type, vec![]).tr(span))
}
"size_of" => {
// TODO: 32-bit
InstCall::Local(Ty::Int(self.target.uint()).tr(span))
}
"alloca" => {
let any = Ty::infer(self.vars().var(span));
let ptr = IType::pointer(any);
InstCall::LocalCall(span, vec![], ptr, Container::FnPointer)
}
"unreachable" => InstCall::Local(Ty::infer(self.vars().var(span)).tr(span)),
"transmute" => {
let param = Ty::infer(self.vars().var(span));
let ptypes = vec![param];
let ret = Ty::infer(self.vars().var(span));
InstCall::LocalCall(span, ptypes, ret, Container::FnPointer)
}
"val_to_ref" => {
let any = Ty::infer(self.vars().var(span));
let ptr = Ty::pointer(any.clone());
let ptypes = vec![any];
let ret = ptr;
InstCall::LocalCall(span, ptypes, ret, Container::FnPointer)
}
_ => {
self.error("unrecognised builtin").eline(span, "").emit();
InstCall::Local(Ty::poison().tr(span))
}
},
hir::Callable::Builtin(name) => builtins::signature(self, span, *name),
hir::Callable::Func(mnfunc) => {
self.type_of_nfunc(span, M(mnfunc.module, mnfunc.key), tanot)
}
Expand Down
71 changes: 3 additions & 68 deletions lumina-compiler/src/mir/lower/expr.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{pat, pat::Merge, Callable, FinError, Lower, MatchBranchLower};
use crate::mir::builtins;
use crate::prelude::*;
use crate::{LISTABLE_CONS, LISTABLE_NEW, LISTABLE_WITH_CAPACITY, STRINGABLE_FROM_RAW_PARTS};
use ast::NFunc;
Expand Down Expand Up @@ -120,62 +121,7 @@ impl<'a, 's> Lower<'a, 's> {
Expr::Call(call, params)
})
}
hir::Callable::Builtin(name) => match *name {
"plus" => self.lower_builtin(params, |p| Expr::Num("plus", Box::new(p))),
"minus" => self.lower_builtin(params, |p| Expr::Num("minus", Box::new(p))),
"mul" => self.lower_builtin(params, |p| Expr::Num("mul", Box::new(p))),
"div" => self.lower_builtin(params, |p| Expr::Num("div", Box::new(p))),
"plus_checked" => {
self.lower_builtin(params, |p| Expr::Num("plus_checked", Box::new(p)))
}
"minus_checked" => {
self.lower_builtin(params, |p| Expr::Num("minus_checked", Box::new(p)))
}
"mul_checked" => {
self.lower_builtin(params, |p| Expr::Num("mul_checked", Box::new(p)))
}
"div_checked" => {
self.lower_builtin(params, |p| Expr::Num("div_checked", Box::new(p)))
}
"array_len" => self.lower_builtin(params, |[p]| Expr::ArrayLen(Box::new(p))),
"array_get" => self.lower_builtin(params, |p| Expr::ArrayAccess(Box::new(p))),
"iabs" => self.lower_builtin(params, |[p]| Expr::IntAbs(Box::new(p))),
"eq" => self.lower_builtin(params, |p| Expr::Cmp("eq", Box::new(p))),
"lt" => self.lower_builtin(params, |p| Expr::Cmp("lt", Box::new(p))),
"gt" => self.lower_builtin(params, |p| Expr::Cmp("gt", Box::new(p))),
"deref" => self.lower_builtin(params, |[inner]| Expr::Deref(Box::new(inner))),
"write" => self.lower_builtin(params, |p| Expr::Write(Box::new(p))),
"offset" => self.lower_builtin(params, |p| Expr::Num("plus", Box::new(p))),
"unreachable" => {
let (name, ty) = tanot.for_entity[0].clone();
assert_eq!(*name, "self");
let ty = self.finalizer().transform(&ty);
self.lower_builtin::<0>(params, |_| Expr::Unreachable(ty))
}
"transmute" => self.lower_builtin(params, |[inner]| inner),
"val_to_ref" => {
self.lower_builtin(params, |[inner]| Expr::ValToRef(Box::new(inner)))
}
"reflect_type" => {
let (name, ty) = tanot.for_entity[0].clone();
assert_eq!(*name, "self");
let ty = self.finalizer().transform(&ty);
Expr::ReflectTypeOf(ty)
}
"size_of" => {
let (name, ty) = tanot.for_entity[0].clone();
assert_eq!(*name, "self");
let ty = self.finalizer().transform(&ty);
Expr::SizeOf(ty)
}
"alloca" => {
let (name, ty) = tanot.for_entity[0].clone();
assert_eq!(*name, "self");
let ty = self.finalizer().transform(&ty);
Expr::Alloca(ty)
}
_ => panic!("unknown builtin: {name}"),
},
hir::Callable::Builtin(name) => builtins::lower(self, *name, params, tanot),
},
hir::Expr::Pass(call, _, params) => match call {
hir::Callable::Func(nfunc) => {
Expand Down Expand Up @@ -317,18 +263,7 @@ impl<'a, 's> Lower<'a, 's> {
Some((rkey.inside(module), params))
}

fn lower_builtin<const N: usize>(
&mut self,
params: &[Tr<hir::Expr<'s>>],
constructor: impl FnOnce([Expr; N]) -> Expr,
) -> Expr {
match <[Expr; N]>::try_from(self.lower_exprs(params)) {
Ok(params) => constructor(params),
Err(_) => Expr::Poison,
}
}

fn lower_exprs(&mut self, exprs: &[Tr<hir::Expr<'s>>]) -> Vec<Expr> {
pub(crate) fn lower_exprs(&mut self, exprs: &[Tr<hir::Expr<'s>>]) -> Vec<Expr> {
exprs
.iter()
.map(|expr| self.lower_expr(expr.as_ref()))
Expand Down
3 changes: 2 additions & 1 deletion lumina-compiler/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ mod func;
pub use func::FunctionStatus;
use func::InstInfo;
use lumina_typesystem::{ImplIndex, Type};
mod builtins;
mod patc;
mod tcheck;

mod tyfmt;

mod lower;
pub use lower::{pat, CallTypes, Callable, ConcreteTyping, Expr, Function};
pub use lower::{pat, CallTypes, Callable, ConcreteTyping, Expr, Function, Lower};
pub type DecTree = pat::DecTree<key::DecisionTreeTail>;
pub type Branching<K> = pat::Branching<K, key::DecisionTreeTail>;

Expand Down
4 changes: 2 additions & 2 deletions luminapath/std/ptr/lib.lm
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ pub fn deref ptr as *a -> a = builtin:deref ptr
// So; we shouldn't need builtin:offset anymore.

// Offset the pointer by a set amount of bytes
pub fn offset ptr by as *a, int -> *a = builtin:offset ptr by
pub fn offset ptr by as *a, int -> *a = builtin:offset ptr (by as uint)

pub fn offsetu ptr by as *a, uint -> *a = builtin:offset ptr (by as int)
pub fn offsetu ptr by as *a, uint -> *a = builtin:offset ptr by

pub fn null as *a = 0 as *a

Expand Down

0 comments on commit 6b31023

Please sign in to comment.