Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use extern functions in dispatch table #90

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions crates/mun_codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ salsa="0.12"
md5="0.6.1"
array-init="0.1.0"
tempfile = "3"
lazy_static = "1.4.0"
paste = "0.1.6"

[dependencies.inkwell]
git = "https://github.com/mun-lang/inkwell"
Expand All @@ -28,6 +28,5 @@ features = ["llvm7-0"]
insta = "0.12.0"

[build-dependencies]
lazy_static = "1.4.0"
semver = "0.9.0"
regex = "1.3.1"
157 changes: 88 additions & 69 deletions crates/mun_codegen/src/code_gen/symbols.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::abi_types::{gen_abi_types, AbiTypes};
use crate::ir::dispatch_table::DispatchTable;
use crate::ir::dispatch_table::{DispatchTable, DispatchableFunction};
use crate::ir::function;
use crate::type_info::TypeInfo;
use crate::values::{BasicValue, GlobalValue};
use crate::IrDatabase;
use hir::{Ty, TypeCtor};
Expand All @@ -12,36 +13,6 @@ use inkwell::{
AddressSpace,
};
use std::collections::HashMap;
use std::hash::{Hash, Hasher};

pub type Guid = [u8; 16];

#[derive(Clone, Eq, Ord, PartialOrd, Debug)]
pub struct TypeInfo {
pub guid: Guid,
pub name: String,
}

impl Hash for TypeInfo {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write(&self.guid)
}
}

impl PartialEq for TypeInfo {
fn eq(&self, other: &Self) -> bool {
self.guid == other.guid
}
}

impl TypeInfo {
fn from_name<S: AsRef<str>>(name: S) -> TypeInfo {
TypeInfo {
name: name.as_ref().to_string(),
guid: md5::compute(name.as_ref()).0,
}
}
}

pub fn type_info_query(db: &impl IrDatabase, ty: Ty) -> TypeInfo {
match ty {
Expand Down Expand Up @@ -91,8 +62,16 @@ fn gen_signature_from_function<D: IrDatabase>(
hir::Visibility::Public => 0,
_ => 1,
};
let ret_type_ir = gen_signature_return_type(db, module, types, function);
let (params_type_ir, num_params) = gen_signature_argument_types(db, module, types, function);
let fn_sig = function.ty(db).callable_sig(db).unwrap();
let ret_type_ir = gen_signature_return_type(db, module, types, fn_sig.ret().clone());

let params_type_ir = gen_type_info_array(
db,
module,
types,
fn_sig.params().iter().map(|ty| db.type_info(ty.clone())),
);
let num_params = fn_sig.params().len();

types.function_signature_type.const_named_struct(&[
name_str.into(),
Expand All @@ -107,48 +86,65 @@ fn gen_signature_from_function<D: IrDatabase>(
])
}

/// Given a function, construct a pointer to a `MunTypeInfo[]` global that represents the argument
/// types of the function; or `null` if the function has no arguments.
fn gen_signature_argument_types<D: IrDatabase>(
/// Construct a `MunFunctionSignature` struct for the specified dispatch table function.
fn gen_signature_from_dispatch_entry<D: IrDatabase>(
db: &D,
module: &Module,
types: &AbiTypes,
function: hir::Function,
) -> (PointerValue, usize) {
let body = function.body(db);
let infer = function.infer(db);

let hir_types = body.params().iter().map(|(p, _)| infer[*p].clone());
function: &DispatchableFunction,
) -> StructValue {
let name_str = intern_string(&module, &function.prototype.name);
// let _visibility = match function.visibility(db) {
// hir::Visibility::Public => 0,
// _ => 1,
// };
let ret_type_ir = gen_signature_return_type_from_type_info(
db,
module,
types,
function.prototype.ret_type.clone(),
);
let params_type_ir = gen_type_info_array(
db,
module,
types,
function.prototype.arg_types.iter().cloned(),
);
let num_params = function.prototype.arg_types.len();

gen_type_info_array(db, module, types, hir_types)
types.function_signature_type.const_named_struct(&[
name_str.into(),
params_type_ir.into(),
ret_type_ir.into(),
module
.get_context()
.i16_type()
.const_int(num_params as u64, false)
.into(),
module.get_context().i8_type().const_int(0, false).into(),
])
}

/// Generates
/// Generates an array of TypeInfo's
fn gen_type_info_array<D: IrDatabase>(
db: &D,
_db: &D,
module: &Module,
types: &AbiTypes,
hir_types: impl Iterator<Item = Ty>,
) -> (PointerValue, usize) {
hir_types: impl Iterator<Item = TypeInfo>,
) -> PointerValue {
let mut hir_types = hir_types.peekable();
if hir_types.peek().is_none() {
(
types
.type_info_type
.ptr_type(AddressSpace::Const)
.const_null(),
0,
)
types
.type_info_type
.ptr_type(AddressSpace::Const)
.const_null()
} else {
let type_infos = hir_types
.map(|ty| type_info_ir(&db.type_info(ty), &module))
.map(|ty| type_info_ir(&ty, &module))
.collect::<Vec<StructValue>>();

let type_array_ir = types.type_info_type.const_array(&type_infos);
(
gen_global(module, &type_array_ir, "").as_pointer_value(),
type_infos.len(),
)
gen_global(module, &type_array_ir, "").as_pointer_value()
}
}

Expand All @@ -158,18 +154,36 @@ fn gen_signature_return_type<D: IrDatabase>(
db: &D,
module: &Module,
types: &AbiTypes,
function: hir::Function,
ret_type: Ty,
) -> PointerValue {
let sig = function.ty(db).callable_sig(db).unwrap();
let ret_type = sig.ret().clone();
if ret_type.is_empty() {
gen_signature_return_type_from_type_info(
db,
module,
types,
if ret_type.is_empty() {
None
} else {
Some(db.type_info(ret_type))
},
)
}

/// Given a function, construct a pointer to a `MunTypeInfo` global that represents the return type
/// of the function; or `null` if the return type is empty.
fn gen_signature_return_type_from_type_info<D: IrDatabase>(
_db: &D,
module: &Module,
types: &AbiTypes,
ret_type: Option<TypeInfo>,
) -> PointerValue {
if let Some(ret_type) = ret_type {
let ret_type_const = type_info_ir(&ret_type, &module);
gen_global(module, &ret_type_const, "").as_pointer_value()
} else {
types
.type_info_type
.ptr_type(AddressSpace::Const)
.const_null()
} else {
let ret_type_const = type_info_ir(&db.type_info(ret_type), &module);
gen_global(module, &ret_type_const, "").as_pointer_value()
}
}

Expand Down Expand Up @@ -216,8 +230,13 @@ fn gen_struct_info_array<'a, D: IrDatabase>(
let name_str = intern_string(&module, &s.name(db).to_string());

let fields = s.fields(db);
let field_types = fields.iter().map(|field| field.ty(db));
let (fields, num_fields) = gen_type_info_array(db, module, types, field_types);
let num_fields = fields.len();
let fields = gen_type_info_array(
db,
module,
types,
fields.iter().map(|field| db.type_info(field.ty(db))),
);

types.struct_info_type.const_named_struct(&[
name_str.into(),
Expand Down Expand Up @@ -259,7 +278,7 @@ fn gen_dispatch_table<D: IrDatabase>(
let signatures: Vec<StructValue> = dispatch_table
.entries()
.iter()
.map(|f| gen_signature_from_function(db, module, types, *f))
.map(|entry| gen_signature_from_dispatch_entry(db, module, types, entry))
.collect();

// Construct an IR array from the signatures
Expand Down
2 changes: 1 addition & 1 deletion crates/mun_codegen/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@



use crate::{code_gen::symbols::TypeInfo, ir::module::ModuleIR, Context};
use crate::{ir::module::ModuleIR, type_info::TypeInfo, Context};
use inkwell::types::StructType;
use inkwell::{types::AnyTypeEnum, OptimizationLevel};
use mun_target::spec::Target;
Expand Down
21 changes: 21 additions & 0 deletions crates/mun_codegen/src/intrinsics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use crate::ir::dispatch_table::FunctionPrototype;
use inkwell::context::Context;
use inkwell::types::FunctionType;

#[macro_use]
mod macros;

/// Defines the properties of an intrinsic function that can be called from Mun. These functions
/// are mostly used internally.
pub trait Intrinsic: Sync {
/// Returns the prototype of the intrinsic
fn prototype(&self) -> FunctionPrototype;

/// Returns the IR type for the function
fn ir_type(&self, context: &Context) -> FunctionType;
}

intrinsics! {
/// Allocates memory from the runtime to use in code.
pub fn malloc(size: u64, alignment: u64) -> *mut u8;
}
30 changes: 30 additions & 0 deletions crates/mun_codegen/src/intrinsics/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
macro_rules! intrinsics{
($($(#[$attr:meta])* pub fn $name:ident($($arg_name:ident:$arg:ty),*) -> $ret:ty;);*) => {
$(
paste::item! {
pub struct [<Intrinsic $name>];
}
paste::item! {
impl Intrinsic for [<Intrinsic $name>] {
fn prototype(&self) -> FunctionPrototype {
FunctionPrototype {
name: stringify!($name).to_owned(),
arg_types: vec![$(<$arg as crate::type_info::HasStaticTypeInfo>::type_info()),*],
ret_type: <$ret as crate::type_info::HasStaticReturnTypeInfo>::return_type_info()
}
}

fn ir_type(&self, context: &Context) -> FunctionType {
let args = vec![$(<$arg as crate::ir::IsBasicIrType>::ir_type(context)),*];
<$ret as crate::ir::IsFunctionReturnType>::fn_type(context, &args, false)
}
}
}
paste::item! {
#[allow(non_upper_case_globals)]
$(#[$attr])* pub const $name:[<Intrinsic $name>] = [<Intrinsic $name>];
}
)*
};
($(#[$attr:meta])*) => {}
}
Loading