Skip to content
Draft
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
26 changes: 13 additions & 13 deletions crates/mun_codegen/src/ir/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
dispatch_table::DispatchTable,
ty::HirTypeCache,
type_table::TypeTable,
value::{Operand, Place, PlaceValue},
value::{Callable, Operand, Place, PlaceValue},
RuntimeArrayValue, RuntimeReferenceValue,
},
module_group::ModuleGroup,
Expand Down Expand Up @@ -422,10 +422,9 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
let allocator_handle = self.get_allocator_handle_ptr();

// Safety: we can be sure that the new intrinsic returns a reference.
let untyped_reference = self
.builder
.build_call(
new_fn_ptr,
let untyped_reference = new_fn_ptr
.call(
&self.builder,
&[type_info_ptr.into(), allocator_handle.into()],
"ref",
)
Expand Down Expand Up @@ -1118,17 +1117,19 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
&self.builder,
function,
);
self.builder
.build_call(ptr_value, args, &function.name(self.db).to_string())
ptr_value.call(&self.builder, args, &function.name(self.db).to_string())
} else {
let llvm_function = self.function_map.get(&function).unwrap_or_else(|| {
panic!(
"missing function value for mun_hir function: '{}'",
function.name(self.db),
)
});
self.builder
.build_call(*llvm_function, args, &function.name(self.db).to_string())
Callable::from_function(*llvm_function).call(
&self.builder,
args,
&function.name(self.db).to_string(),
)
}
}

Expand Down Expand Up @@ -1507,10 +1508,9 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
// An object pointer adds an extra layer of indirection to allow for hot
// reloading. To make it struct type agnostic, it is stored in a `*const
// *mut std::ffi::c_void`.
let untyped_array_ptr = self
.builder
.build_call(
new_array_fn_ptr,
let untyped_array_ptr = new_array_fn_ptr
.call(
&self.builder,
&[
type_info_ptr.into(),
length_value.into(),
Expand Down
55 changes: 29 additions & 26 deletions crates/mun_codegen/src/ir/dispatch_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@ use std::{
use inkwell::{
context::Context,
module::Module,
targets::TargetData,
types::{BasicTypeEnum, FunctionType},
values::{BasicValueEnum, CallableValue},
values::BasicValueEnum,
};
use mun_hir::{Body, Expr, ExprId, HirDatabase, InferenceResult};
use rustc_hash::FxHashSet;

use crate::{
intrinsics::Intrinsic,
ir::{function, ty::HirTypeCache},
ir::{function, ty::HirTypeCache, value::Callable},
module_group::ModuleGroup,
type_info::{HasStaticTypeId, TypeId},
};
Expand All @@ -35,16 +34,14 @@ use crate::{
/// hot reloading within Mun.
#[derive(Debug, Eq, PartialEq)]
pub struct DispatchTable<'ink> {
// The LLVM context in which all LLVM types live
context: &'ink Context,
// The target for which to create the dispatch table
target: TargetData,
// This contains the function that map to the DispatchTable struct fields
function_to_idx: HashMap<mun_hir::Function, usize>,
// Prototype to function index
prototype_to_idx: HashMap<FunctionPrototype, usize>,
// This contains an ordered list of all the function in the dispatch table
entries: Vec<DispatchableFunction>,
// LLVM signatures for entries at the same index.
signatures: Vec<FunctionType<'ink>>,
// Contains a reference to the global value containing the DispatchTable
table_ref: Option<inkwell::values::GlobalValue<'ink>>,
//
Expand Down Expand Up @@ -88,7 +85,7 @@ impl<'ink> DispatchTable<'ink> {
table_ref: Option<inkwell::values::GlobalValue<'ink>>,
builder: &inkwell::builder::Builder<'ink>,
function: mun_hir::Function,
) -> CallableValue<'ink> {
) -> Callable<'ink> {
let function_name = function.name(db).to_string();

// Get the index of the function
Expand All @@ -97,7 +94,13 @@ impl<'ink> DispatchTable<'ink> {
.get(&function)
.expect("unknown function");

Self::gen_function_lookup_by_index(table_ref, builder, &function_name, index)
Self::gen_function_lookup_by_index(
table_ref,
builder,
&function_name,
index,
self.signatures[index],
)
}

/// Generates a function lookup through the `DispatchTable`, equivalent to
Expand All @@ -108,7 +111,7 @@ impl<'ink> DispatchTable<'ink> {
table_ref: Option<inkwell::values::GlobalValue<'ink>>,
builder: &inkwell::builder::Builder<'ink>,
intrinsic: &impl Intrinsic,
) -> CallableValue<'ink> {
) -> Callable<'ink> {
let prototype = intrinsic.prototype();

// Get the index of the intrinsic
Expand All @@ -117,7 +120,13 @@ impl<'ink> DispatchTable<'ink> {
.get(&prototype)
.expect("unknown function");

Self::gen_function_lookup_by_index(table_ref, builder, &prototype.name, index)
Self::gen_function_lookup_by_index(
table_ref,
builder,
&prototype.name,
index,
self.signatures[index],
)
}

/// Generates a function lookup through the `DispatchTable`, equivalent to
Expand All @@ -128,7 +137,8 @@ impl<'ink> DispatchTable<'ink> {
builder: &inkwell::builder::Builder<'ink>,
function_name: &str,
index: usize,
) -> CallableValue<'ink> {
signature: FunctionType<'ink>,
) -> Callable<'ink> {
// Get the internal table reference
let table_ref = table_ref.expect("no dispatch table defined");

Expand All @@ -144,11 +154,10 @@ impl<'ink> DispatchTable<'ink> {
panic!("could not get {function_name} (index: {index}) from dispatch table")
});

builder
let pointer = builder
.build_load(ptr_to_function_ptr, &format!("{function_name}_ptr"))
.into_pointer_value()
.try_into()
.expect("Pointer value is not a valid function pointer.")
.into_pointer_value();
Callable::new(pointer, signature)
}

/// Returns the value that represents the dispatch table in IR or `None` if
Expand All @@ -166,12 +175,8 @@ impl<'ink> DispatchTable<'ink> {
/// A struct that can be used to build the dispatch table from HIR.
pub(crate) struct DispatchTableBuilder<'db, 'ink, 't> {
db: &'db dyn HirDatabase,
// The LLVM context in which all LLVM types live
context: &'ink Context,
// The module in which all values live
// Module that owns the dispatch table global.
module: &'t Module<'ink>,
// The target for which to create the dispatch table
target_data: TargetData,
// Converts HIR ty's to inkwell types
hir_types: &'t HirTypeCache<'db, 'ink>,
// This contains the functions that map to the DispatchTable struct fields
Expand Down Expand Up @@ -199,7 +204,6 @@ impl<'db, 'ink, 't> DispatchTableBuilder<'db, 'ink, 't> {
/// Creates a new builder that can generate a dispatch function.
pub fn new(
context: &'ink Context,
target_data: TargetData,
db: &'db dyn HirDatabase,
module: &'t Module<'ink>,
intrinsics: &BTreeMap<FunctionPrototype, FunctionType<'ink>>,
Expand All @@ -208,9 +212,7 @@ impl<'db, 'ink, 't> DispatchTableBuilder<'db, 'ink, 't> {
) -> Self {
let mut table = Self {
db,
context,
module,
target_data,
function_to_idx: HashMap::default(),
prototype_to_idx: HashMap::default(),
entries: Vec::default(),
Expand Down Expand Up @@ -332,6 +334,8 @@ impl<'db, 'ink, 't> DispatchTableBuilder<'db, 'ink, 't> {
///
/// Returns the `DispatchTable` and a set of dependencies for the module.
pub fn build(self) -> (DispatchTable<'ink>, FxHashSet<mun_hir::Module>) {
let signatures = self.entries.iter().map(|entry| entry.ir_type).collect();

// Construct the table body from all the entries in the dispatch table
let table_body: Vec<BasicTypeEnum<'ink>> = self
.entries
Expand Down Expand Up @@ -383,12 +387,11 @@ impl<'db, 'ink, 't> DispatchTableBuilder<'db, 'ink, 't> {

(
DispatchTable {
context: self.context,
target: self.target_data,
function_to_idx: self.function_to_idx,
prototype_to_idx: self.prototype_to_idx,
table_ref: self.table_ref,
table_type,
signatures,
entries: self
.entries
.into_iter()
Expand Down
1 change: 0 additions & 1 deletion crates/mun_codegen/src/ir/file_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ pub(crate) fn gen_file_group_ir<'ink>(
// Collect all exposed functions' bodies.
let mut dispatch_table_builder = DispatchTableBuilder::new(
code_gen.context,
code_gen.target_machine.get_target_data(),
code_gen.db,
&llvm_module,
&intrinsics_map,
Expand Down
47 changes: 45 additions & 2 deletions crates/mun_codegen/src/ir/value.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,53 @@
use inkwell::{
builder::Builder,
types::BasicTypeEnum,
values::{BasicValueEnum, InstructionValue, PointerValue},
types::{BasicTypeEnum, FunctionType},
values::{
BasicMetadataValueEnum, BasicValueEnum, CallSiteValue, CallableValue, FunctionValue,
InstructionValue, PointerValue,
},
AddressSpace,
};
use mun_hir::Ty;

/// A function pointer paired with the signature required to call it.
#[derive(Clone, Copy)]
pub(crate) struct Callable<'ink> {
pointer: PointerValue<'ink>,
signature: FunctionType<'ink>,
}

impl<'ink> Callable<'ink> {
pub(crate) fn new(pointer: PointerValue<'ink>, signature: FunctionType<'ink>) -> Self {
debug_assert_eq!(
pointer.get_type(),
signature.ptr_type(AddressSpace::default())
);
Self { pointer, signature }
}

pub(crate) fn from_function(function: FunctionValue<'ink>) -> Self {
Self::new(
function.as_global_value().as_pointer_value(),
function.get_type(),
)
}

pub(crate) fn call(
self,
builder: &Builder<'ink>,
args: &[BasicMetadataValueEnum<'ink>],
name: &str,
) -> CallSiteValue<'ink> {
debug_assert_eq!(
self.pointer.get_type(),
self.signature.ptr_type(AddressSpace::default())
);
let callable = CallableValue::try_from(self.pointer)
.expect("callable pointer must have a function signature");
builder.build_call(callable, args, name)
}
}

/// An SSA value paired with the Mun type that gives the value its meaning.
#[derive(Clone)]
pub(crate) struct Operand<'ink> {
Expand Down
Loading