diff --git a/crates/mun_abi/c b/crates/mun_abi/c
index 1380c1959..fe351ecde 160000
--- a/crates/mun_abi/c
+++ b/crates/mun_abi/c
@@ -1 +1 @@
-Subproject commit 1380c1959532df7c889ad994e8ff6338e0105cab
+Subproject commit fe351ecdec31624373f92851089e665f1314840f
diff --git a/crates/mun_abi/src/autogen.rs b/crates/mun_abi/src/autogen.rs
index 8eeb2b693..92a987042 100644
--- a/crates/mun_abi/src/autogen.rs
+++ b/crates/mun_abi/src/autogen.rs
@@ -9,9 +9,9 @@ use crate::{Privacy, StructMemoryKind, TypeGroup};
#[doc = ""]
#[doc = " GUIDs are generated by taking the MD5 hash of a type's name."]
#[doc = ""]
-#[doc = "
"]
+#[doc = " "]
#[repr(C)]
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct Guid {
#[doc = " 16-byte MD5 hash"]
pub b: [u8; 16usize],
@@ -236,6 +236,8 @@ pub struct StructInfo {
pub field_sizes: *const u16,
#[doc = " Number of fields"]
pub num_fields: u16,
+ #[doc = " Struct memory alignment"]
+ pub alignment: u16,
#[doc = " Struct memory kind"]
pub memory_kind: StructMemoryKind,
}
@@ -312,8 +314,18 @@ fn bindgen_test_layout_StructInfo() {
)
);
assert_eq!(
- unsafe { &(*(::std::ptr::null::())).memory_kind as *const _ as usize },
+ unsafe { &(*(::std::ptr::null::())).alignment as *const _ as usize },
42usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(StructInfo),
+ "::",
+ stringify!(alignment)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::())).memory_kind as *const _ as usize },
+ 44usize,
concat!(
"Offset of field: ",
stringify!(StructInfo),
diff --git a/crates/mun_abi/src/autogen_impl.rs b/crates/mun_abi/src/autogen_impl.rs
index f6c7b08c2..f2aad2d20 100644
--- a/crates/mun_abi/src/autogen_impl.rs
+++ b/crates/mun_abi/src/autogen_impl.rs
@@ -162,6 +162,13 @@ impl StructInfo {
)
})
}
+
+ /// Returns the size of the struct
+ pub fn size(&self) -> usize {
+ (self.field_offsets().last().cloned().unwrap_or(0)
+ + self.field_sizes().last().cloned().unwrap_or(0))
+ .into()
+ }
}
impl fmt::Display for StructInfo {
@@ -468,6 +475,7 @@ mod tests {
field_types: &[&TypeInfo],
field_offsets: &[u16],
field_sizes: &[u16],
+ alignment: u16,
memory_kind: StructMemoryKind,
) -> StructInfo {
assert!(field_names.len() == field_types.len());
@@ -481,6 +489,7 @@ mod tests {
field_offsets: field_offsets.as_ptr(),
field_sizes: field_sizes.as_ptr(),
num_fields: field_names.len() as u16,
+ alignment,
memory_kind,
}
}
@@ -490,7 +499,7 @@ mod tests {
#[test]
fn test_struct_info_name() {
let struct_name = CString::new(FAKE_STRUCT_NAME).expect("Invalid fake struct name.");
- let struct_info = fake_struct_info(&struct_name, &[], &[], &[], &[], Default::default());
+ let struct_info = fake_struct_info(&struct_name, &[], &[], &[], &[], 1, Default::default());
assert_eq!(struct_info.name(), FAKE_STRUCT_NAME);
}
@@ -508,6 +517,7 @@ mod tests {
field_types,
field_offsets,
field_sizes,
+ 1,
Default::default(),
);
@@ -515,6 +525,7 @@ mod tests {
assert_eq!(struct_info.field_types(), field_types);
assert_eq!(struct_info.field_offsets(), field_offsets);
assert_eq!(struct_info.field_sizes(), field_sizes);
+ assert_eq!(struct_info.size(), 0);
}
#[test]
@@ -527,6 +538,7 @@ mod tests {
let field_types = &[&type_info];
let field_offsets = &[1];
let field_sizes = &[2];
+ let alignment = 1;
let struct_name = CString::new(FAKE_STRUCT_NAME).expect("Invalid fake struct name.");
let struct_info = fake_struct_info(
&struct_name,
@@ -534,6 +546,7 @@ mod tests {
field_types,
field_offsets,
field_sizes,
+ alignment,
Default::default(),
);
@@ -543,28 +556,42 @@ mod tests {
assert_eq!(struct_info.field_types(), field_types);
assert_eq!(struct_info.field_offsets(), field_offsets);
assert_eq!(struct_info.field_sizes(), field_sizes);
+ assert_eq!(
+ struct_info.size() as u16,
+ field_offsets.last().unwrap() + field_sizes.last().unwrap()
+ )
}
- fn fake_module_info(
- path: &CStr,
- functions: &[FunctionInfo],
- types: &[&TypeInfo],
- ) -> ModuleInfo {
- ModuleInfo {
- path: path.as_ptr(),
- functions: functions.as_ptr(),
- num_functions: functions.len() as u32,
- types: types.as_ptr().cast::<*const TypeInfo>(),
- num_types: types.len() as u32,
- }
+ #[test]
+ fn test_struct_info_alignment() {
+ let struct_name = CString::new(FAKE_STRUCT_NAME).expect("Invalid fake struct name.");
+ let struct_alignment = 4;
+ let struct_info = fake_struct_info(
+ &struct_name,
+ &[],
+ &[],
+ &[],
+ &[],
+ struct_alignment,
+ Default::default(),
+ );
+
+ assert_eq!(struct_info.alignment, struct_alignment);
}
#[test]
fn test_struct_info_memory_kind_gc() {
let struct_name = CString::new(FAKE_STRUCT_NAME).expect("Invalid fake struct name.");
let struct_memory_kind = StructMemoryKind::GC;
- let struct_info =
- fake_struct_info(&struct_name, &[], &[], &[], &[], struct_memory_kind.clone());
+ let struct_info = fake_struct_info(
+ &struct_name,
+ &[],
+ &[],
+ &[],
+ &[],
+ 1,
+ struct_memory_kind.clone(),
+ );
assert_eq!(struct_info.memory_kind, struct_memory_kind);
}
@@ -573,12 +600,33 @@ mod tests {
fn test_struct_info_memory_kind_value() {
let struct_name = CString::new(FAKE_STRUCT_NAME).expect("Invalid fake struct name.");
let struct_memory_kind = StructMemoryKind::Value;
- let struct_info =
- fake_struct_info(&struct_name, &[], &[], &[], &[], struct_memory_kind.clone());
+ let struct_info = fake_struct_info(
+ &struct_name,
+ &[],
+ &[],
+ &[],
+ &[],
+ 1,
+ struct_memory_kind.clone(),
+ );
assert_eq!(struct_info.memory_kind, struct_memory_kind);
}
+ fn fake_module_info(
+ path: &CStr,
+ functions: &[FunctionInfo],
+ types: &[&TypeInfo],
+ ) -> ModuleInfo {
+ ModuleInfo {
+ path: path.as_ptr(),
+ functions: functions.as_ptr(),
+ num_functions: functions.len() as u32,
+ types: types.as_ptr().cast::<*const TypeInfo>(),
+ num_types: types.len() as u32,
+ }
+ }
+
const FAKE_MODULE_PATH: &str = "path::to::module";
#[test]
@@ -616,7 +664,7 @@ mod tests {
let functions = &[fn_info];
let struct_name = CString::new(FAKE_STRUCT_NAME).expect("Invalid fake struct name");
- let struct_info = fake_struct_info(&struct_name, &[], &[], &[], &[], Default::default());
+ let struct_info = fake_struct_info(&struct_name, &[], &[], &[], &[], 1, Default::default());
let struct_type_info = fake_struct_type_info(&struct_name, struct_info);
let types = &[unsafe { mem::transmute(&struct_type_info) }];
diff --git a/crates/mun_codegen/src/code_gen.rs b/crates/mun_codegen/src/code_gen.rs
index f4e5c5804..7eae75402 100644
--- a/crates/mun_codegen/src/code_gen.rs
+++ b/crates/mun_codegen/src/code_gen.rs
@@ -1,23 +1,29 @@
use crate::code_gen::linker::LinkerError;
use crate::IrDatabase;
use failure::Fail;
-use hir::FileId;
-use inkwell::module::Module;
-use inkwell::passes::{PassManager, PassManagerBuilder};
-use inkwell::targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target};
-use inkwell::OptimizationLevel;
+use hir::{FileId, RelativePathBuf};
+use inkwell::targets::TargetData;
+use inkwell::{
+ module::{Linkage, Module},
+ passes::{PassManager, PassManagerBuilder},
+ targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target},
+ types::StructType,
+ values::{BasicValue, GlobalValue, IntValue, PointerValue, UnnamedAddress},
+ AddressSpace, OptimizationLevel,
+};
use std::io::{self, Write};
-use std::path::Path;
+use std::{
+ path::{Path, PathBuf},
+ sync::Arc,
+};
-mod abi_types;
mod linker;
+pub mod symbols;
#[derive(Debug, Fail)]
enum CodeGenerationError {
#[fail(display = "{}", 0)]
LinkerError(#[fail(cause)] LinkerError),
- #[fail(display = "error linking modules: {}", 0)]
- ModuleLinkerError(String),
#[fail(display = "unknown target triple: {}", 0)]
UnknownTargetTriple(String),
#[fail(display = "error creating target machine")]
@@ -34,87 +40,121 @@ impl From for CodeGenerationError {
}
}
-/// Construct a shared object for the given `hir::FileId` at the specified output file location.
-pub fn write_module_shared_object(
- db: &impl IrDatabase,
+pub struct ModuleBuilder<'a, D: IrDatabase> {
+ db: &'a D,
file_id: FileId,
- output_file_path: &Path,
-) -> Result<(), failure::Error> {
- let target = db.target();
-
- // Construct a module for the assembly
- let assembly_module = db.context().create_module(
- output_file_path
- .file_name()
- .and_then(|s| s.to_str())
- .unwrap_or("unknown"),
- );
-
- // Initialize the x86 target
- Target::initialize_x86(&InitializationConfig::default());
-
- // Construct the LLVM target from the specified target.
- let llvm_target = Target::from_triple(&target.llvm_target)
- .map_err(|e| CodeGenerationError::UnknownTargetTriple(e.to_string()))?;
- assembly_module.set_target(&llvm_target);
-
- // Construct target machine for machine code generation
- let target_machine = llvm_target
- .create_target_machine(
- &target.llvm_target,
- &target.options.cpu,
- &target.options.features,
- db.optimization_lvl(),
- RelocMode::PIC,
- CodeModel::Default,
- )
- .ok_or(CodeGenerationError::CouldNotCreateTargetMachine)?;
-
- // Generate IR for the module and clone it so that we can modify it without modifying the
- // cached value.
- let module = db.module_ir(file_id);
- assembly_module
- .link_in_module(module.llvm_module.clone())
- .map_err(|e| CodeGenerationError::ModuleLinkerError(e.to_string()))?;
-
- // Generate the `get_info` method.
- symbols::gen_reflection_ir(
- db,
- &target_machine,
- &assembly_module,
- &module.types,
- &module.functions,
- &module.dispatch_table,
- );
-
- // Optimize the assembly module
- optimize_module(&assembly_module, db.optimization_lvl());
-
- // Debug print the IR
- //println!("{}", assembly_module.print_to_string().to_string());
-
- // Generate object file
- let obj_file = {
- let obj = target_machine
- .write_to_memory_buffer(&assembly_module, FileType::Object)
- .map_err(|e| CodeGenerationError::CodeGenerationError(e.to_string()))?;
- let mut obj_file = tempfile::NamedTempFile::new()
- .map_err(CodeGenerationError::CouldNotCreateObjectFile)?;
- obj_file
- .write(obj.as_slice())
- .map_err(CodeGenerationError::CouldNotCreateObjectFile)?;
- obj_file
- };
-
- // Construct a linker for the target
- let mut linker = linker::create_with_target(&target);
- linker.add_object(obj_file.path())?;
-
- // Link the object
- linker.build_shared_object(&output_file_path)?;
- linker.finalize()?;
-
- Ok(())
+ _target: inkwell::targets::Target,
+ target_machine: inkwell::targets::TargetMachine,
+ assembly_module: Arc,
+}
+
+impl<'a, D: IrDatabase> ModuleBuilder<'a, D> {
+ /// Construct module for the given `hir::FileId` at the specified output file location.
+ pub fn new(db: &'a mut D, file_id: FileId) -> Result {
+ let target = db.target();
+
+ // Construct a module for the assembly
+ let assembly_module = Arc::new(
+ db.context()
+ .create_module(db.file_relative_path(file_id).as_str()),
+ );
+
+ // Initialize the x86 target
+ Target::initialize_x86(&InitializationConfig::default());
+
+ // Retrieve the LLVM target using the specified target.
+ let llvm_target = Target::from_triple(&target.llvm_target)
+ .map_err(|e| CodeGenerationError::UnknownTargetTriple(e.to_string()))?;
+ assembly_module.set_target(&llvm_target);
+
+ // Construct target machine for machine code generation
+ let target_machine = llvm_target
+ .create_target_machine(
+ &target.llvm_target,
+ &target.options.cpu,
+ &target.options.features,
+ db.optimization_lvl(),
+ RelocMode::PIC,
+ CodeModel::Default,
+ )
+ .ok_or(CodeGenerationError::CouldNotCreateTargetMachine)?;
+
+ // Initialize the module and target data
+ db.set_module(assembly_module.clone());
+
+ Ok(Self {
+ db,
+ file_id,
+ _target: llvm_target,
+ target_machine,
+ assembly_module,
+ })
+ }
+
+ /// Construct a shared object at the specified output file location.
+ pub fn finalize(&self, out_dir: Option<&Path>) -> Result {
+ // Generate IR for the module and clone it so that we can modify it without modifying the
+ // cached value.
+ let module = self.db.module_ir(self.file_id);
+
+ // Generate the `get_info` method.
+ symbols::gen_reflection_ir(
+ self.db,
+ &self.assembly_module,
+ &module.functions,
+ &module.dispatch_table,
+ &module.type_table,
+ );
+
+ // Optimize the assembly module
+ optimize_module(&self.assembly_module, self.db.optimization_lvl());
+
+ // Debug print the IR
+ //println!("{}", assembly_module.print_to_string().to_string());
+
+ // Generate object file
+ let obj_file = {
+ let obj = self
+ .target_machine
+ .write_to_memory_buffer(&self.assembly_module, FileType::Object)
+ .map_err(|e| CodeGenerationError::CodeGenerationError(e.to_string()))?;
+ let mut obj_file = tempfile::NamedTempFile::new()
+ .map_err(CodeGenerationError::CouldNotCreateObjectFile)?;
+ obj_file
+ .write(obj.as_slice())
+ .map_err(CodeGenerationError::CouldNotCreateObjectFile)?;
+ obj_file
+ };
+
+ let target = self.db.target();
+
+ // Construct a linker for the target
+ let mut linker = linker::create_with_target(&target);
+ linker.add_object(obj_file.path())?;
+
+ let output_path = assembly_output_path(self.db, self.file_id, out_dir);
+
+ // Link the object
+ linker.build_shared_object(&output_path)?;
+ linker.finalize()?;
+
+ Ok(output_path)
+ }
+}
+/// Computes the output path for the assembly of the specified file.
+fn assembly_output_path(db: &D, file_id: FileId, out_dir: Option<&Path>) -> PathBuf {
+ let relative_path: RelativePathBuf = db.file_relative_path(file_id);
+ let original_filename = Path::new(relative_path.file_name().unwrap());
+
+ // Add the `munlib` suffix to the original filename
+ let output_file_name = original_filename.with_extension("munlib");
+
+ // If there is an out dir specified, prepend the output directory
+ if let Some(out_dir) = out_dir {
+ out_dir.join(output_file_name)
+ } else {
+ output_file_name
+ }
}
/// Optimizes the specified LLVM `Module` using the default passes for the given
@@ -128,4 +168,83 @@ fn optimize_module(module: &Module, optimization_lvl: OptimizationLevel) {
module_pass_manager.run_on(module);
}
-pub mod symbols;
+/// Intern a string by constructing a global value. Looks something like this:
+/// ```c
+/// const char[] GLOBAL_ = "str";
+/// ```
+pub(crate) fn intern_string(module: &Module, string: &str, name: &str) -> PointerValue {
+ let value = module.get_context().const_string(string, true);
+ gen_global(module, &value, name).as_pointer_value()
+}
+
+/// Construct a global from the specified value
+pub(crate) fn gen_global(module: &Module, value: &dyn BasicValue, name: &str) -> GlobalValue {
+ let global = module.add_global(value.as_basic_value_enum().get_type(), None, name);
+ global.set_linkage(Linkage::Private);
+ global.set_constant(true);
+ global.set_unnamed_address(UnnamedAddress::Global);
+ global.set_initializer(value);
+ global
+}
+
+/// Generates a global array from the specified list of strings
+pub(crate) fn gen_string_array(
+ module: &Module,
+ strings: impl Iterator- ,
+ name: &str,
+) -> PointerValue {
+ let str_type = module.get_context().i8_type().ptr_type(AddressSpace::Const);
+
+ let mut strings = strings.peekable();
+ if strings.peek().is_none() {
+ str_type.ptr_type(AddressSpace::Const).const_null()
+ } else {
+ let strings = strings
+ .map(|s| intern_string(module, &s, name))
+ .collect::>();
+
+ let strings_ir = str_type.const_array(&strings);
+ gen_global(module, &strings_ir, "").as_pointer_value()
+ }
+}
+
+/// Generates a global array from the specified list of struct pointers
+pub(crate) fn gen_struct_ptr_array(
+ module: &Module,
+ ir_type: StructType,
+ ptrs: &[PointerValue],
+ name: &str,
+) -> PointerValue {
+ if ptrs.is_empty() {
+ ir_type
+ .ptr_type(AddressSpace::Const)
+ .ptr_type(AddressSpace::Const)
+ .const_null()
+ } else {
+ let ptr_array_ir = ir_type.ptr_type(AddressSpace::Const).const_array(&ptrs);
+
+ gen_global(module, &ptr_array_ir, name).as_pointer_value()
+ }
+}
+
+/// Generates a global array from the specified list of integers
+pub(crate) fn gen_u16_array(module: &Module, integers: impl Iterator
- ) -> PointerValue {
+ let u16_type = module.get_context().i16_type();
+
+ let mut integers = integers.peekable();
+ if integers.peek().is_none() {
+ u16_type.ptr_type(AddressSpace::Const).const_null()
+ } else {
+ let integers = integers
+ .map(|i| u16_type.const_int(i, false))
+ .collect::>();
+
+ let array_ir = u16_type.const_array(&integers);
+ gen_global(module, &array_ir, "").as_pointer_value()
+ }
+}
+
+/// Create an inkwell TargetData from the target in the database
+pub(crate) fn target_data_query(db: &impl IrDatabase) -> Arc {
+ Arc::new(TargetData::create(&db.target().data_layout))
+}
diff --git a/crates/mun_codegen/src/code_gen/linker.rs b/crates/mun_codegen/src/code_gen/linker.rs
index d829584c9..3bfa1c080 100644
--- a/crates/mun_codegen/src/code_gen/linker.rs
+++ b/crates/mun_codegen/src/code_gen/linker.rs
@@ -163,6 +163,7 @@ impl Linker for MsvcLinker {
self.args.push("/DLL".to_owned());
self.args.push("/NOENTRY".to_owned());
self.args.push("/EXPORT:get_info".to_owned());
+ self.args.push("/EXPORT:set_allocator_handle".to_owned());
self.args.push(format!("/IMPLIB:{}", dll_lib_path_str));
self.args.push(format!("/OUT:{}", dll_path_str));
Ok(())
diff --git a/crates/mun_codegen/src/code_gen/symbols.rs b/crates/mun_codegen/src/code_gen/symbols.rs
index 6396cd06c..d827f458b 100644
--- a/crates/mun_codegen/src/code_gen/symbols.rs
+++ b/crates/mun_codegen/src/code_gen/symbols.rs
@@ -1,111 +1,57 @@
-use super::abi_types::{gen_abi_types, AbiTypes};
+use crate::code_gen::{gen_global, gen_struct_ptr_array, intern_string};
use crate::ir::{
+ abi_types::{gen_abi_types, AbiTypes},
dispatch_table::{DispatchTable, DispatchableFunction},
function,
+ type_table::TypeTable,
};
-use crate::type_info::{TypeGroup, TypeInfo};
-use crate::values::{BasicValue, GlobalValue};
-use crate::{CodeGenParams, IrDatabase};
+use crate::type_info::TypeInfo;
+use crate::IrDatabase;
use hir::Ty;
use inkwell::{
attributes::Attribute,
module::{Linkage, Module},
- targets::TargetMachine,
- values::{FunctionValue, IntValue, PointerValue, StructValue, UnnamedAddress},
+ values::{FunctionValue, GlobalValue, PointerValue, StructValue},
AddressSpace,
};
-use std::collections::{HashMap, HashSet};
-
-struct GlobalArrayValue(GlobalValue, usize);
-
-/// Construct an IR `MunTypeInfo` struct value for the specified `TypeInfo`
-fn type_info_ir(
- db: &D,
- target: &TargetMachine,
- module: &Module,
- types: &AbiTypes,
- global_type_info_lookup_table: &mut HashMap,
- type_info: TypeInfo,
-) -> PointerValue {
- if let Some(value) = global_type_info_lookup_table.get(&type_info) {
- *value
- } else {
- let context = module.get_context();
- let guid_values: [IntValue; 16] = array_init::array_init(|i| {
- context
- .i8_type()
- .const_int(u64::from(type_info.guid.b[i]), false)
- });
-
- let type_info_ir = context.const_struct(
- &[
- context.i8_type().const_array(&guid_values).into(),
- intern_string(module, &type_info.name).into(),
- context
- .i8_type()
- .const_int(type_info.group.clone().into(), false)
- .into(),
- ],
- false,
- );
-
- let type_info_ir = match type_info.group {
- TypeGroup::FundamentalTypes => type_info_ir,
- TypeGroup::StructTypes(s) => {
- let struct_info_ir =
- gen_struct_info(db, target, module, types, global_type_info_lookup_table, s);
- context.const_struct(&[type_info_ir.into(), struct_info_ir.into()], false)
- }
- };
-
- let type_info_ir = gen_global(module, &type_info_ir, "").as_pointer_value();
- global_type_info_lookup_table.insert(type_info, type_info_ir);
- type_info_ir
- }
-}
-
-/// Intern a string by constructing a global value. Looks something like this:
-/// ```c
-/// const char[] GLOBAL_ = "str";
-/// ```
-fn intern_string(module: &Module, str: &str) -> PointerValue {
- let value = module.get_context().const_string(str, true);
- gen_global(module, &value, ".str").as_pointer_value()
-}
+use std::collections::HashMap;
/// Construct a `MunFunctionSignature` struct for the specified HIR function.
fn gen_signature_from_function(
db: &D,
module: &Module,
types: &AbiTypes,
- global_type_info_lookup_table: &HashMap,
+ type_table: &TypeTable,
function: hir::Function,
) -> StructValue {
- let name_str = intern_string(&module, &function.name(db).to_string());
+ let name = function.name(db).to_string();
+
+ let name_ir = intern_string(&module, &name, &name);
let _visibility = match function.visibility(db) {
hir::Visibility::Public => 0,
_ => 1,
};
let fn_sig = function.ty(db).callable_sig(db).unwrap();
- let ret_type_ir = gen_signature_return_type(
- db,
- types,
- global_type_info_lookup_table,
- fn_sig.ret().clone(),
- );
+ let ret_type_ir = gen_signature_return_type(db, types, type_table, fn_sig.ret().clone());
+
+ let param_types: Vec = fn_sig
+ .params()
+ .iter()
+ .map(|ty| type_table.get(&db.type_info(ty.clone())).unwrap())
+ .collect();
- let params_type_ir = gen_type_info_ptr_array(
+ let param_types = gen_struct_ptr_array(
module,
- types,
- global_type_info_lookup_table,
- fn_sig.params().iter().map(|ty| db.type_info(ty.clone())),
+ types.type_info_type,
+ ¶m_types,
+ &format!("fn_sig::<{}>::arg_types", name),
);
let num_params = fn_sig.params().len();
types.function_signature_type.const_named_struct(&[
- name_str.into(),
- params_type_ir.into(),
+ name_ir.into(),
+ param_types.into(),
ret_type_ir.into(),
module
.get_context()
@@ -121,10 +67,14 @@ fn gen_signature_from_dispatch_entry(
db: &D,
module: &Module,
types: &AbiTypes,
- global_type_info_lookup_table: &HashMap,
+ type_table: &TypeTable,
function: &DispatchableFunction,
) -> StructValue {
- let name_str = intern_string(&module, &function.prototype.name);
+ let name_str = intern_string(
+ &module,
+ &function.prototype.name,
+ &format!("fn_sig::<{}>::name", function.prototype.name),
+ );
// let _visibility = match function.visibility(db) {
// hir::Visibility::Public => 0,
// _ => 1,
@@ -132,20 +82,26 @@ fn gen_signature_from_dispatch_entry(
let ret_type_ir = gen_signature_return_type_from_type_info(
db,
types,
- global_type_info_lookup_table,
+ type_table,
function.prototype.ret_type.clone(),
);
- let params_type_ir = gen_type_info_ptr_array(
+ let param_types: Vec = function
+ .prototype
+ .arg_types
+ .iter()
+ .map(|type_info| type_table.get(type_info).unwrap())
+ .collect();
+ let param_types = gen_struct_ptr_array(
module,
- types,
- global_type_info_lookup_table,
- function.prototype.arg_types.iter().cloned(),
+ types.type_info_type,
+ ¶m_types,
+ &format!("{}_param_types", function.prototype.name),
);
let num_params = function.prototype.arg_types.len();
types.function_signature_type.const_named_struct(&[
name_str.into(),
- params_type_ir.into(),
+ param_types.into(),
ret_type_ir.into(),
module
.get_context()
@@ -156,76 +112,18 @@ fn gen_signature_from_dispatch_entry(
])
}
-/// Recursively expands an array of TypeInfo into an array of IR pointers
-fn expand_type_info(
- db: &D,
- target: &TargetMachine,
- module: &Module,
- types: &AbiTypes,
- global_type_info_lookup_table: &mut HashMap,
- hir_types: impl Iterator
- ,
-) -> PointerValue {
- let mut hir_types = hir_types.peekable();
- if hir_types.peek().is_none() {
- types
- .type_info_type
- .ptr_type(AddressSpace::Const)
- .ptr_type(AddressSpace::Const)
- .const_null()
- } else {
- let type_infos = hir_types
- .map(|ty| type_info_ir(db, target, module, types, global_type_info_lookup_table, ty))
- .collect::>();
-
- let type_array_ir = types
- .type_info_type
- .ptr_type(AddressSpace::Const)
- .const_array(&type_infos);
-
- gen_global(module, &type_array_ir, "").as_pointer_value()
- }
-}
-
-/// Generates IR for an array of TypeInfo values
-fn gen_type_info_ptr_array(
- module: &Module,
- types: &AbiTypes,
- global_type_info_lookup_table: &HashMap,
- hir_types: impl Iterator
- ,
-) -> PointerValue {
- let mut hir_types = hir_types.peekable();
- if hir_types.peek().is_none() {
- types
- .type_info_type
- .ptr_type(AddressSpace::Const)
- .ptr_type(AddressSpace::Const)
- .const_null()
- } else {
- let type_infos = hir_types
- .map(|ty| *global_type_info_lookup_table.get(&ty).unwrap())
- .collect::>();
-
- let type_array_ir = types
- .type_info_type
- .ptr_type(AddressSpace::Const)
- .const_array(&type_infos);
-
- gen_global(module, &type_array_ir, "").as_pointer_value()
- }
-}
-
/// 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(
db: &D,
types: &AbiTypes,
- global_type_info_lookup_table: &HashMap,
+ type_table: &TypeTable,
ret_type: Ty,
) -> PointerValue {
gen_signature_return_type_from_type_info(
db,
types,
- global_type_info_lookup_table,
+ type_table,
if ret_type.is_empty() {
None
} else {
@@ -239,11 +137,11 @@ fn gen_signature_return_type(
fn gen_signature_return_type_from_type_info(
_db: &D,
types: &AbiTypes,
- global_type_info_lookup_table: &HashMap,
+ type_table: &TypeTable,
ret_type: Option,
) -> PointerValue {
if let Some(ret_type) = ret_type {
- *global_type_info_lookup_table.get(&ret_type).unwrap()
+ type_table.get(&ret_type).unwrap()
} else {
types
.type_info_type
@@ -258,9 +156,9 @@ fn gen_function_info_array<'a, D: IrDatabase>(
db: &D,
module: &Module,
types: &AbiTypes,
- global_type_info_lookup_table: &HashMap,
+ type_table: &TypeTable,
functions: impl Iterator
- ,
-) -> GlobalArrayValue {
+) -> GlobalValue {
let function_infos: Vec = functions
.map(|(f, value)| {
// Get the function from the cloned module and modify the linkage of the function.
@@ -270,8 +168,7 @@ fn gen_function_info_array<'a, D: IrDatabase>(
value.set_linkage(Linkage::Private);
// Generate the signature from the function
- let signature =
- gen_signature_from_function(db, module, types, global_type_info_lookup_table, *f);
+ let signature = gen_signature_from_function(db, module, types, type_table, *f);
// Generate the function info value
types.function_info_type.const_named_struct(&[
@@ -280,126 +177,8 @@ fn gen_function_info_array<'a, D: IrDatabase>(
])
})
.collect();
- let num_functions = function_infos.len();
let function_infos = types.function_info_type.const_array(&function_infos);
-
- GlobalArrayValue(
- gen_global(module, &function_infos, "fn.get_info.functions"),
- num_functions,
- )
-}
-
-/// Construct a global that holds a reference to all structs. e.g.:
-/// MunStructInfo[] info = { ... }
-fn gen_struct_info(
- db: &D,
- target: &TargetMachine,
- module: &Module,
- types: &AbiTypes,
- global_type_info_lookup_table: &mut HashMap,
- s: hir::Struct,
-) -> StructValue {
- let name_str = intern_string(&module, &s.name(db).to_string());
-
- let fields = s.fields(db);
- let field_names = fields.iter().map(|field| field.name(db).to_string());
- let (field_names, num_fields) = gen_string_array(module, field_names);
-
- let field_types = expand_type_info(
- db,
- target,
- module,
- types,
- global_type_info_lookup_table,
- fields.iter().map(|field| db.type_info(field.ty(db))),
- );
-
- let target_data = target.get_target_data();
- let t = db.struct_ty(s);
- let field_offsets =
- (0..fields.len()).map(|idx| target_data.offset_of_element(&t, idx as u32).unwrap());
- let (field_offsets, _) = gen_u16_array(module, field_offsets);
-
- let field_sizes = fields.iter().map(|field| {
- target_data.get_store_size(&db.type_ir(
- field.ty(db),
- CodeGenParams {
- make_marshallable: false,
- },
- ))
- });
- let (field_sizes, _) = gen_u16_array(module, field_sizes);
-
- types.struct_info_type.const_named_struct(&[
- name_str.into(),
- field_names.into(),
- field_types.into(),
- field_offsets.into(),
- field_sizes.into(),
- module
- .get_context()
- .i16_type()
- .const_int(num_fields as u64, false)
- .into(),
- module
- .get_context()
- .i8_type()
- .const_int(s.data(db).memory_kind.clone().into(), false)
- .into(),
- ])
-}
-
-/// Constructs a global from the specified list of strings
-fn gen_string_array(
- module: &Module,
- strings: impl Iterator
- ,
-) -> (PointerValue, usize) {
- let str_type = module.get_context().i8_type().ptr_type(AddressSpace::Const);
-
- let mut strings = strings.peekable();
- if strings.peek().is_none() {
- (str_type.ptr_type(AddressSpace::Const).const_null(), 0)
- } else {
- let strings = strings
- .map(|s| intern_string(module, &s))
- .collect::>();
-
- let strings_ir = str_type.const_array(&strings);
- (
- gen_global(module, &strings_ir, "").as_pointer_value(),
- strings.len(),
- )
- }
-}
-
-/// Constructs a global from the specified list of strings
-fn gen_u16_array(module: &Module, integers: impl Iterator
- ) -> (PointerValue, usize) {
- let u16_type = module.get_context().i16_type();
-
- let mut integers = integers.peekable();
- if integers.peek().is_none() {
- (u16_type.ptr_type(AddressSpace::Const).const_null(), 0)
- } else {
- let integers = integers
- .map(|i| u16_type.const_int(i, false))
- .collect::>();
-
- let array_ir = u16_type.const_array(&integers);
- (
- gen_global(module, &array_ir, "").as_pointer_value(),
- integers.len(),
- )
- }
-}
-
-/// Construct a global from the specified value
-fn gen_global(module: &Module, value: &dyn BasicValue, name: &str) -> GlobalValue {
- let global = module.add_global(value.as_basic_value_enum().get_type(), None, name);
- global.set_linkage(Linkage::Private);
- global.set_constant(true);
- global.set_unnamed_address(UnnamedAddress::Global);
- global.set_initializer(value);
- global
+ gen_global(module, &function_infos, "fn.get_info.functions")
}
/// Generate the dispatch table information. e.g.:
@@ -410,22 +189,14 @@ fn gen_dispatch_table(
db: &D,
module: &Module,
types: &AbiTypes,
- global_type_info_lookup_table: &HashMap,
dispatch_table: &DispatchTable,
+ type_table: &TypeTable,
) -> StructValue {
// Generate a vector with all the function signatures
let signatures: Vec = dispatch_table
.entries()
.iter()
- .map(|entry| {
- gen_signature_from_dispatch_entry(
- db,
- module,
- types,
- global_type_info_lookup_table,
- entry,
- )
- })
+ .map(|entry| gen_signature_from_dispatch_entry(db, module, types, type_table, entry))
.collect();
// Construct an IR array from the signatures
@@ -470,62 +241,41 @@ fn gen_dispatch_table(
/// for the ABI that `get_info` exposes.
pub(super) fn gen_reflection_ir(
db: &impl IrDatabase,
- target: &TargetMachine,
module: &Module,
- types: &HashSet,
function_map: &HashMap,
dispatch_table: &DispatchTable,
+ type_table: &TypeTable,
) {
// Get all the types
let abi_types = gen_abi_types(module.get_context());
- let mut global_type_info_lookup_table = HashMap::new();
- let num_types = types.len();
- let types = expand_type_info(
- db,
- target,
- module,
- &abi_types,
- &mut global_type_info_lookup_table,
- types.iter().cloned(),
- );
-
- let GlobalArrayValue(function_info, num_functions) = gen_function_info_array(
- db,
- module,
- &abi_types,
- &global_type_info_lookup_table,
- function_map.iter(),
- );
+ let num_functions = function_map.len();
+ let function_info =
+ gen_function_info_array(db, module, &abi_types, type_table, function_map.iter());
// Construct the module info struct
let module_info = abi_types.module_info_type.const_named_struct(&[
- intern_string(module, "").into(),
+ intern_string(module, "", "module_info::path").into(),
function_info.as_pointer_value().into(),
module
.get_context()
.i32_type()
.const_int(num_functions as u64, false)
.into(),
- types.into(),
+ type_table.pointer_value().into(),
module
.get_context()
.i32_type()
- .const_int(num_types as u64, false)
+ .const_int(type_table.num_types() as u64, false)
.into(),
]);
// Construct the dispatch table struct
- let dispatch_table = gen_dispatch_table(
- db,
- module,
- &abi_types,
- &global_type_info_lookup_table,
- dispatch_table,
- );
+ let dispatch_table = gen_dispatch_table(db, module, &abi_types, dispatch_table, type_table);
// Construct the actual `get_info` function
gen_get_info_fn(db, module, &abi_types, module_info, dispatch_table);
+ gen_set_allocator_handle_fn(db, module);
}
/// Construct the actual `get_info` function.
@@ -617,3 +367,33 @@ fn gen_get_info_fn(
// Run the function optimizer on the generate function
function::create_pass_manager(&module, db.optimization_lvl()).run_on(&get_symbols_fn);
}
+
+fn gen_set_allocator_handle_fn(db: &impl IrDatabase, module: &Module) {
+ let context = module.get_context();
+ let allocator_handle_type = context.i8_type().ptr_type(AddressSpace::Generic);
+
+ let set_allocator_handle_fn_type = context
+ .void_type()
+ .fn_type(&[allocator_handle_type.into()], false);
+
+ let set_allocator_handle_fn = module.add_function(
+ "set_allocator_handle",
+ set_allocator_handle_fn_type,
+ Some(Linkage::DLLExport),
+ );
+
+ let builder = db.context().create_builder();
+ let body_ir = db
+ .context()
+ .append_basic_block(&set_allocator_handle_fn, "body");
+ builder.position_at_end(&body_ir);
+
+ if let Some(allocator_handle_global) = module.get_global("allocatorHandle") {
+ builder.build_store(
+ allocator_handle_global.as_pointer_value(),
+ set_allocator_handle_fn.get_nth_param(0).unwrap(),
+ );
+ }
+
+ builder.build_return(None);
+}
diff --git a/crates/mun_codegen/src/db.rs b/crates/mun_codegen/src/db.rs
index 332c4ee73..1e88e5007 100644
--- a/crates/mun_codegen/src/db.rs
+++ b/crates/mun_codegen/src/db.rs
@@ -1,8 +1,12 @@
#![allow(clippy::type_repetition_in_bounds)]
use crate::{ir::module::ModuleIR, type_info::TypeInfo, CodeGenParams, Context};
-use inkwell::types::StructType;
-use inkwell::{types::AnyTypeEnum, OptimizationLevel};
+use inkwell::{
+ module::Module,
+ targets::TargetData,
+ types::{AnyTypeEnum, StructType},
+ OptimizationLevel,
+};
use mun_target::spec::Target;
use std::sync::Arc;
@@ -14,6 +18,10 @@ pub trait IrDatabase: hir::HirDatabase {
#[salsa::input]
fn context(&self) -> Arc;
+ /// Returns the LLVM module that should be used for all generation steps.
+ #[salsa::input]
+ fn module(&self) -> Arc;
+
/// Gets the optimization level for generation.
#[salsa::input]
fn optimization_lvl(&self) -> OptimizationLevel;
@@ -22,6 +30,10 @@ pub trait IrDatabase: hir::HirDatabase {
#[salsa::input]
fn target(&self) -> Target;
+ /// Returns the target machine's data layout for code generation.
+ #[salsa::invoke(crate::code_gen::target_data_query)]
+ fn target_data(&self) -> Arc;
+
/// Given a type and code generation parameters, return the corresponding IR type.
#[salsa::invoke(crate::ir::ty::ir_query)]
fn type_ir(&self, ty: hir::Ty, params: CodeGenParams) -> AnyTypeEnum;
diff --git a/crates/mun_codegen/src/intrinsics.rs b/crates/mun_codegen/src/intrinsics.rs
index d4106231d..46492553c 100644
--- a/crates/mun_codegen/src/intrinsics.rs
+++ b/crates/mun_codegen/src/intrinsics.rs
@@ -2,6 +2,7 @@ use crate::ir::dispatch_table::FunctionPrototype;
use crate::type_info::TypeInfo;
use inkwell::context::Context;
use inkwell::types::FunctionType;
+use std::ffi;
#[macro_use]
mod macros;
@@ -17,8 +18,9 @@ pub trait Intrinsic: Sync {
}
intrinsics! {
- /// Allocates memory from the runtime to use in code.
- pub fn malloc(size: u64, alignment: u64) -> *mut u8;
- /// Allocates memory for and clones the specified type located at `src` into it.
- pub fn clone(src: *const u8, ty: *const TypeInfo) -> *mut u8;
+ /// Allocates memory for the specified `type` in the allocator referred to by `alloc_handle`.
+ pub fn new(type: *const TypeInfo, alloc_handle: *mut ffi::c_void) -> *const *mut ffi::c_void;
+ /// Allocates memory for and clones the specified type located at `src` into it. Memory is
+ /// allocated in the allocator referred to by `alloc_handle`.
+ pub fn clone(src: *const ffi::c_void, alloc_handle: *mut ffi::c_void) -> *const *mut ffi::c_void;
}
diff --git a/crates/mun_codegen/src/ir.rs b/crates/mun_codegen/src/ir.rs
index fab6ed00e..74e1b103b 100644
--- a/crates/mun_codegen/src/ir.rs
+++ b/crates/mun_codegen/src/ir.rs
@@ -5,13 +5,16 @@ use inkwell::types::{
};
use inkwell::AddressSpace;
+pub(crate) mod abi_types;
pub mod adt;
pub mod body;
#[macro_use]
pub(crate) mod dispatch_table;
pub mod function;
+mod intrinsics;
pub mod module;
pub mod ty;
+pub(crate) mod type_table;
/// Try to down cast an `AnyTypeEnum` into a `BasicTypeEnum`.
fn try_convert_any_to_basic(ty: AnyTypeEnum) -> Option {
@@ -191,6 +194,20 @@ impl IsPointerType for *const TypeInfo {
}
}
+// HACK: Manually add `*const c_void`
+impl IsPointerType for *const std::ffi::c_void {
+ fn ir_type(context: &Context) -> PointerType {
+ context.i8_type().ptr_type(AddressSpace::Const)
+ }
+}
+
+// HACK: Manually add `*mut c_void`
+impl IsPointerType for *mut std::ffi::c_void {
+ fn ir_type(context: &Context) -> PointerType {
+ context.i8_type().ptr_type(AddressSpace::Generic)
+ }
+}
+
impl> IsPointerType for *mut T {
fn ir_type(context: &Context) -> PointerType {
T::ir_type(context).ptr_type(AddressSpace::Generic)
diff --git a/crates/mun_codegen/src/code_gen/abi_types.rs b/crates/mun_codegen/src/ir/abi_types.rs
similarity index 96%
rename from crates/mun_codegen/src/code_gen/abi_types.rs
rename to crates/mun_codegen/src/ir/abi_types.rs
index 4ed140cb1..cc06b71be 100644
--- a/crates/mun_codegen/src/code_gen/abi_types.rs
+++ b/crates/mun_codegen/src/ir/abi_types.rs
@@ -2,7 +2,7 @@ use inkwell::context::ContextRef;
use inkwell::types::{ArrayType, IntType, StructType};
use inkwell::AddressSpace;
-pub(super) struct AbiTypes {
+pub(crate) struct AbiTypes {
pub guid_type: ArrayType,
pub type_group_type: IntType,
pub privacy_type: IntType,
@@ -16,7 +16,7 @@ pub(super) struct AbiTypes {
}
/// Returns an `AbiTypes` struct that contains references to all LLVM ABI types.
-pub(super) fn gen_abi_types(context: ContextRef) -> AbiTypes {
+pub(crate) fn gen_abi_types(context: ContextRef) -> AbiTypes {
let str_type = context.i8_type().ptr_type(AddressSpace::Const);
// Construct the `MunGuid` type
@@ -78,6 +78,7 @@ pub(super) fn gen_abi_types(context: ContextRef) -> AbiTypes {
context.i16_type().ptr_type(AddressSpace::Const).into(), // field_offsets
context.i16_type().ptr_type(AddressSpace::Const).into(), // field_sizes
context.i16_type().into(), // num_fields
+ context.i16_type().into(), // alignment
context.i8_type().into(), // memory_kind
],
false,
diff --git a/crates/mun_codegen/src/ir/body.rs b/crates/mun_codegen/src/ir/body.rs
index 2411b6b63..7676d8f4f 100644
--- a/crates/mun_codegen/src/ir/body.rs
+++ b/crates/mun_codegen/src/ir/body.rs
@@ -1,6 +1,7 @@
use crate::intrinsics;
use crate::{
- ir::dispatch_table::DispatchTable, ir::try_convert_any_to_basic, CodeGenParams, IrDatabase,
+ ir::{dispatch_table::DispatchTable, try_convert_any_to_basic, type_table::TypeTable},
+ CodeGenParams, IrDatabase,
};
use hir::{
ArenaId, ArithOp, BinaryOp, Body, CmpOp, Expr, ExprId, HirDisplay, InferenceResult, Literal,
@@ -8,14 +9,13 @@ use hir::{
};
use inkwell::{
builder::Builder,
- module::Module,
values::{BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue, StructValue},
AddressSpace, FloatPredicate, IntPredicate,
};
use std::{collections::HashMap, mem, sync::Arc};
use inkwell::basic_block::BasicBlock;
-use inkwell::values::{AggregateValueEnum, PointerValue};
+use inkwell::values::{AggregateValueEnum, GlobalValue, PointerValue};
struct LoopInfo {
break_values: Vec<(
@@ -27,7 +27,6 @@ struct LoopInfo {
pub(crate) struct BodyIrGenerator<'a, 'b, D: IrDatabase> {
db: &'a D,
- module: &'a Module,
body: Arc,
infer: Arc,
builder: Builder,
@@ -37,34 +36,37 @@ pub(crate) struct BodyIrGenerator<'a, 'b, D: IrDatabase> {
pat_to_name: HashMap,
function_map: &'a HashMap,
dispatch_table: &'b DispatchTable,
+ type_table: &'b TypeTable,
active_loop: Option,
hir_function: hir::Function,
params: CodeGenParams,
+ allocator_handle_global: Option,
}
impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
pub fn new(
db: &'a D,
- module: &'a Module,
- hir_function: hir::Function,
- ir_function: FunctionValue,
+ function: (hir::Function, FunctionValue),
function_map: &'a HashMap,
dispatch_table: &'b DispatchTable,
+ type_table: &'b TypeTable,
params: CodeGenParams,
+ allocator_handle_global: Option,
) -> Self {
+ let (hir_function, ir_function) = function;
+
// Get the type information from the `hir::Function`
let body = hir_function.body(db);
let infer = hir_function.infer(db);
// Construct a builder for the IR function
- let context = module.get_context();
+ let context = db.context();
let builder = context.create_builder();
let body_ir = context.append_basic_block(&ir_function, "body");
builder.position_at_end(&body_ir);
BodyIrGenerator {
db,
- module,
body,
infer,
builder,
@@ -74,9 +76,11 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
pat_to_name: HashMap::default(),
function_map,
dispatch_table,
+ type_table,
active_loop: None,
hir_function,
params,
+ allocator_handle_global,
}
}
@@ -238,21 +242,16 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
fn gen_literal(&mut self, lit: &Literal) -> BasicValueEnum {
match lit {
Literal::Int(v) => self
- .module
- .get_context()
+ .db
+ .context()
.i64_type()
.const_int(unsafe { mem::transmute::(*v) }, true)
.into(),
- Literal::Float(v) => self
- .module
- .get_context()
- .f64_type()
- .const_float(*v as f64)
- .into(),
+ Literal::Float(v) => self.db.context().f64_type().const_float(*v as f64).into(),
Literal::Bool(value) => {
- let ty = self.module.get_context().bool_type();
+ let ty = self.db.context().bool_type();
if *value {
ty.const_all_ones().into()
} else {
@@ -266,7 +265,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
/// Constructs an empty struct value e.g. `{}`
fn gen_empty(&mut self) -> BasicValueEnum {
- self.module.get_context().const_struct(&[], false).into()
+ self.db.context().const_struct(&[], false).into()
}
/// Allocate a struct literal either on the stack or the heap based on the type of the struct.
@@ -301,22 +300,39 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
struct_lit: StructValue,
) -> BasicValueEnum {
let struct_ir_ty = self.db.struct_ty(hir_struct);
- let malloc_fn_ptr = self
+ let new_fn_ptr = self
.dispatch_table
- .gen_intrinsic_lookup(&self.builder, &intrinsics::malloc);
- let mem_ptr = self
+ .gen_intrinsic_lookup(&self.builder, &intrinsics::new);
+
+ let type_info_ptr = self
+ .type_table
+ .gen_type_info_lookup(&self.builder, &self.db.type_info(hir_struct.ty(self.db)));
+
+ // HACK: We should be able to use pointers for built-in struct types like `TypeInfo` in intrinsics
+ let type_info_ptr = self.builder.build_bitcast(
+ type_info_ptr,
+ self.db.context().i8_type().ptr_type(AddressSpace::Const),
+ "type_info_ptr_to_i8_ptr",
+ );
+
+ let allocator_handle = self.builder.build_load(
+ self.allocator_handle_global
+ .expect("no allocator handle was specified, this is required for structs")
+ .as_pointer_value(),
+ "allocator_handle",
+ );
+
+ let object_ptr = self
.builder
- .build_call(
- malloc_fn_ptr,
- &[
- struct_ir_ty.size_of().unwrap().into(),
- struct_ir_ty.get_alignment().into(),
- ],
- "malloc",
- )
+ .build_call(new_fn_ptr, &[type_info_ptr, allocator_handle], "new")
.try_as_basic_value()
.left()
- .unwrap();
+ .unwrap()
+ .into_pointer_value();
+ let mem_ptr = self
+ .builder
+ .build_load(object_ptr, "mem_ptr")
+ .into_pointer_value();
let struct_ptr = self
.builder
.build_bitcast(
@@ -326,7 +342,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
)
.into_pointer_value();
self.builder.build_store(struct_ptr, struct_lit);
- struct_ptr.into()
+ object_ptr.into()
}
/// Generates IR for a record literal, e.g. `Foo { a: 1.23, b: 4 }`
@@ -463,21 +479,26 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
/// Given an expression and the type of the expression, optionally dereference the value.
fn opt_deref_value(&mut self, ty: hir::Ty, value: BasicValueEnum) -> BasicValueEnum {
+ /// Derefs a heap-allocated value. As we introduce a layer of indirection for hot
+ /// reloading, we need to first load the pointer that points to the memory block.
+ fn deref_heap_value(builder: &Builder, value: BasicValueEnum) -> BasicValueEnum {
+ let mem_ptr = builder
+ .build_load(value.into_pointer_value(), "mem_ptr")
+ .into_pointer_value();
+
+ builder.build_load(mem_ptr, "deref")
+ }
+
match ty {
hir::Ty::Apply(hir::ApplicationTy {
ctor: hir::TypeCtor::Struct(s),
..
}) => match s.data(self.db).memory_kind {
- hir::StructMemoryKind::GC => {
- self.builder.build_load(value.into_pointer_value(), "deref")
- }
- hir::StructMemoryKind::Value => {
- if self.params.make_marshallable {
- self.builder.build_load(value.into_pointer_value(), "deref")
- } else {
- value
- }
+ hir::StructMemoryKind::GC => deref_heap_value(&self.builder, value),
+ hir::StructMemoryKind::Value if self.params.make_marshallable => {
+ deref_heap_value(&self.builder, value)
}
+ hir::StructMemoryKind::Value => value,
},
_ => value,
}
@@ -746,7 +767,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
.into_int_value();
// Generate the code blocks to branch to
- let context = self.module.get_context();
+ let context = self.db.context();
let mut then_block = context.append_basic_block(&self.fn_value, "then");
let else_block_and_expr = match &else_branch {
Some(else_branch) => Some((
@@ -868,7 +889,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
condition_expr: ExprId,
body_expr: ExprId,
) -> Option {
- let context = self.module.get_context();
+ let context = self.db.context();
let cond_block = context.append_basic_block(&self.fn_value, "whilecond");
let loop_block = context.append_basic_block(&self.fn_value, "while");
let exit_block = context.append_basic_block(&self.fn_value, "afterwhile");
@@ -907,7 +928,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
}
fn gen_loop(&mut self, _expr: ExprId, body_expr: ExprId) -> Option {
- let context = self.module.get_context();
+ let context = self.db.context();
let loop_block = context.append_basic_block(&self.fn_value, "loop");
let exit_block = context.append_basic_block(&self.fn_value, "exit");
diff --git a/crates/mun_codegen/src/ir/dispatch_table.rs b/crates/mun_codegen/src/ir/dispatch_table.rs
index 65071fb57..af9eaff15 100644
--- a/crates/mun_codegen/src/ir/dispatch_table.rs
+++ b/crates/mun_codegen/src/ir/dispatch_table.rs
@@ -1,4 +1,3 @@
-use crate::intrinsics;
use crate::values::FunctionValue;
use crate::{CodeGenParams, IrDatabase};
use inkwell::module::Module;
@@ -8,7 +7,7 @@ use inkwell::values::{BasicValueEnum, PointerValue};
use crate::intrinsics::Intrinsic;
use crate::type_info::TypeInfo;
use hir::{Body, Expr, ExprId, InferenceResult};
-use std::collections::HashMap;
+use std::collections::{BTreeMap, HashMap};
use std::sync::Arc;
/// A dispatch table in IR is a struct that contains pointers to all functions that are called from
@@ -36,7 +35,7 @@ pub struct DispatchTable {
}
/// A `FunctionPrototype` defines a unique signature that can be added to the dispatch table.
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct FunctionPrototype {
pub name: String,
pub arg_types: Vec,
@@ -150,8 +149,12 @@ struct TypedDispatchableFunction {
impl<'a, D: IrDatabase> DispatchTableBuilder<'a, D> {
/// Creates a new builder that can generate a dispatch function.
- pub fn new(db: &'a D, module: &'a Module) -> Self {
- DispatchTableBuilder {
+ pub fn new(
+ db: &'a D,
+ module: &'a Module,
+ intrinsics: BTreeMap,
+ ) -> Self {
+ let mut table = DispatchTableBuilder {
db,
module,
function_to_idx: Default::default(),
@@ -159,7 +162,26 @@ impl<'a, D: IrDatabase> DispatchTableBuilder<'a, D> {
entries: Default::default(),
table_ref: None,
table_type: module.get_context().opaque_struct_type("DispatchTable"),
+ };
+
+ if !intrinsics.is_empty() {
+ table.ensure_table_ref();
+
+ // Use a `BTreeMap` to guarantee deterministically ordered output
+ for (prototype, ir_type) in intrinsics.into_iter() {
+ let index = table.entries.len();
+ table.entries.push(TypedDispatchableFunction {
+ function: DispatchableFunction {
+ prototype: prototype.clone(),
+ hir: None,
+ },
+ ir_type,
+ });
+
+ table.prototype_to_idx.insert(prototype, index);
+ }
}
+ table
}
/// Creates the global dispatch table in the module if it does not exist.
@@ -180,46 +202,11 @@ impl<'a, D: IrDatabase> DispatchTableBuilder<'a, D> {
if let Expr::Call { callee, .. } = expr {
match infer[*callee].as_callable_def() {
Some(hir::CallableDef::Function(def)) => self.collect_fn_def(def),
- Some(hir::CallableDef::Struct(s)) => {
- // self.collect_intrinsic(&intrinsics::new);
- self.collect_intrinsic(&intrinsics::clone);
- // self.collect_intrinsic(&intrinsics::drop);
- if s.data(self.db).memory_kind == hir::StructMemoryKind::GC {
- self.collect_intrinsic(&intrinsics::malloc)
- }
- }
+ Some(hir::CallableDef::Struct(_)) => (),
None => panic!("expected a callable expression"),
}
}
- if let Expr::RecordLit { .. } = expr {
- let struct_ty = infer[expr_id].clone();
- let hir_struct = struct_ty.as_struct().unwrap(); // Can only really get here if the type is a struct
- // self.collect_intrinsic(&intrinsics::new);
- self.collect_intrinsic(&intrinsics::clone);
- // self.collect_intrinsic(&intrinsics::drop);
- if hir_struct.data(self.db).memory_kind == hir::StructMemoryKind::GC {
- self.collect_intrinsic(&intrinsics::malloc)
- }
- }
-
- if let Expr::Path(path) = expr {
- let resolver = hir::resolver_for_expr(body.clone(), self.db, expr_id);
- let resolution = resolver
- .resolve_path_without_assoc_items(self.db, path)
- .take_values()
- .expect("unknown path");
-
- if let hir::Resolution::Def(hir::ModuleDef::Struct(s)) = resolution {
- // self.collect_intrinsic(&intrinsics::new);
- self.collect_intrinsic(&intrinsics::clone);
- // self.collect_intrinsic(&intrinsics::drop);
- if s.data(self.db).memory_kind == hir::StructMemoryKind::GC {
- self.collect_intrinsic(&intrinsics::malloc)
- }
- }
- }
-
// Recurse further
expr.walk_child_exprs(|expr_id| self.collect_expr(expr_id, body, infer))
}
@@ -272,38 +259,12 @@ impl<'a, D: IrDatabase> DispatchTableBuilder<'a, D> {
}
}
- /// Collects a call to an intrinsic function.
- #[allow(clippy::map_entry)]
- fn collect_intrinsic(&mut self, intrinsic: &impl Intrinsic) {
- self.ensure_table_ref();
-
- // If the function is not yet contained in the table add it
- let prototype = intrinsic.prototype();
- if !self.prototype_to_idx.contains_key(&prototype) {
- let index = self.entries.len();
- self.entries.push(TypedDispatchableFunction {
- function: DispatchableFunction {
- prototype: prototype.clone(),
- hir: None,
- },
- ir_type: intrinsic.ir_type(&self.module.get_context()),
- });
-
- self.prototype_to_idx.insert(prototype, index);
- }
- }
-
/// Collect all the call expressions from the specified body with the given type inference
/// result.
pub fn collect_body(&mut self, body: &Arc, infer: &InferenceResult) {
self.collect_expr(body.body_expr(), body, infer);
}
- /// Collect the call expression from the body of a wrapper for the specified function.
- pub fn collect_wrapper_body(&mut self, _function: hir::Function) {
- self.collect_intrinsic(&intrinsics::malloc)
- }
-
/// This creates the final DispatchTable with all *called* functions from within the module
/// # Parameters
/// * **functions**: Mapping of *defined* Mun functions to their respective IR values.
diff --git a/crates/mun_codegen/src/ir/function.rs b/crates/mun_codegen/src/ir/function.rs
index a50bfbc6b..8dbd2c078 100644
--- a/crates/mun_codegen/src/ir/function.rs
+++ b/crates/mun_codegen/src/ir/function.rs
@@ -1,6 +1,5 @@
-use crate::ir::body::BodyIrGenerator;
-use crate::ir::dispatch_table::DispatchTable;
-use crate::values::FunctionValue;
+use crate::ir::{body::BodyIrGenerator, dispatch_table::DispatchTable, type_table::TypeTable};
+use crate::values::{FunctionValue, GlobalValue};
use crate::{CodeGenParams, IrDatabase, Module, OptimizationLevel};
use inkwell::passes::{PassManager, PassManagerBuilder};
use inkwell::types::AnyTypeEnum;
@@ -43,52 +42,48 @@ pub(crate) fn gen_signature(
/// Generates the body of a `hir::Function` for an associated `FunctionValue`.
pub(crate) fn gen_body<'a, 'b, D: IrDatabase>(
db: &'a D,
- hir_function: hir::Function,
- llvm_function: FunctionValue,
- module: &'a Module,
+ function: (hir::Function, FunctionValue),
llvm_functions: &'a HashMap,
dispatch_table: &'b DispatchTable,
-) -> FunctionValue {
+ type_table: &'b TypeTable,
+ allocator_handle_global: Option,
+) {
let mut code_gen = BodyIrGenerator::new(
db,
- module,
- hir_function,
- llvm_function,
+ function,
llvm_functions,
dispatch_table,
+ type_table,
CodeGenParams {
make_marshallable: false,
},
+ allocator_handle_global,
);
code_gen.gen_fn_body();
-
- llvm_function
}
/// Generates the body of a wrapper around `hir::Function` for its associated
/// `FunctionValue`
pub(crate) fn gen_wrapper_body<'a, 'b, D: IrDatabase>(
db: &'a D,
- hir_function: hir::Function,
- llvm_function: FunctionValue,
- module: &'a Module,
+ function: (hir::Function, FunctionValue),
llvm_functions: &'a HashMap,
dispatch_table: &'b DispatchTable,
-) -> FunctionValue {
+ type_table: &'b TypeTable,
+ allocator_handle_global: Option,
+) {
let mut code_gen = BodyIrGenerator::new(
db,
- module,
- hir_function,
- llvm_function,
+ function,
llvm_functions,
dispatch_table,
+ type_table,
CodeGenParams {
make_marshallable: true,
},
+ allocator_handle_global,
);
code_gen.gen_fn_wrapper();
-
- llvm_function
}
diff --git a/crates/mun_codegen/src/ir/intrinsics.rs b/crates/mun_codegen/src/ir/intrinsics.rs
new file mode 100644
index 000000000..34059b15a
--- /dev/null
+++ b/crates/mun_codegen/src/ir/intrinsics.rs
@@ -0,0 +1,97 @@
+use crate::intrinsics::{self, Intrinsic};
+use crate::ir::dispatch_table::FunctionPrototype;
+use crate::IrDatabase;
+use hir::{Body, Expr, ExprId, InferenceResult};
+use inkwell::module::Module;
+use inkwell::types::FunctionType;
+use std::collections::BTreeMap;
+use std::sync::Arc;
+
+// Use a `BTreeMap` to guarantee deterministically ordered output
+pub type IntrinsicsMap = BTreeMap;
+
+fn collect_intrinsic(module: &Module, entries: &mut IntrinsicsMap, intrinsic: &impl Intrinsic) {
+ let prototype = intrinsic.prototype();
+ entries
+ .entry(prototype)
+ .or_insert_with(|| intrinsic.ir_type(&module.get_context()));
+}
+
+fn collect_expr(
+ db: &D,
+ module: &Module,
+ entries: &mut IntrinsicsMap,
+ needs_alloc: &mut bool,
+ expr_id: ExprId,
+ body: &Arc,
+ infer: &InferenceResult,
+) {
+ let expr = &body[expr_id];
+
+ // If this expression is a call, store it in the dispatch table
+ if let Expr::Call { callee, .. } = expr {
+ match infer[*callee].as_callable_def() {
+ Some(hir::CallableDef::Struct(_)) => {
+ collect_intrinsic(module, entries, &intrinsics::new);
+ collect_intrinsic(module, entries, &intrinsics::clone);
+ // self.collect_intrinsic(module, entries, &intrinsics::drop);
+ *needs_alloc = true;
+ }
+ Some(hir::CallableDef::Function(_)) => (),
+ None => panic!("expected a callable expression"),
+ }
+ }
+
+ if let Expr::RecordLit { .. } = expr {
+ collect_intrinsic(module, entries, &intrinsics::new);
+ collect_intrinsic(module, entries, &intrinsics::clone);
+ // self.collect_intrinsic(module, entries, &intrinsics::drop);
+ *needs_alloc = true;
+ }
+
+ if let Expr::Path(path) = expr {
+ let resolver = hir::resolver_for_expr(body.clone(), db, expr_id);
+ let resolution = resolver
+ .resolve_path_without_assoc_items(db, path)
+ .take_values()
+ .expect("unknown path");
+
+ if let hir::Resolution::Def(hir::ModuleDef::Struct(_)) = resolution {
+ collect_intrinsic(module, entries, &intrinsics::new);
+ collect_intrinsic(module, entries, &intrinsics::clone);
+ // self.collect_intrinsic( module, entries, &intrinsics::drop);
+ *needs_alloc = true;
+ }
+ }
+
+ // Recurse further
+ expr.walk_child_exprs(|expr_id| {
+ collect_expr(db, module, entries, needs_alloc, expr_id, body, infer)
+ })
+}
+
+pub fn collect_fn_body(
+ db: &D,
+ module: &Module,
+ entries: &mut IntrinsicsMap,
+ needs_alloc: &mut bool,
+ body: &Arc,
+ infer: &InferenceResult,
+) {
+ collect_expr(
+ db,
+ module,
+ entries,
+ needs_alloc,
+ body.body_expr(),
+ body,
+ infer,
+ );
+}
+
+pub fn collect_wrapper_body(module: &Module, entries: &mut IntrinsicsMap, needs_alloc: &mut bool) {
+ collect_intrinsic(module, entries, &intrinsics::new);
+ collect_intrinsic(module, entries, &intrinsics::clone);
+ // self.collect_intrinsic(entries, &intrinsics::drop, module);
+ *needs_alloc = true;
+}
diff --git a/crates/mun_codegen/src/ir/module.rs b/crates/mun_codegen/src/ir/module.rs
index 0bc472de2..2fa8677e3 100644
--- a/crates/mun_codegen/src/ir/module.rs
+++ b/crates/mun_codegen/src/ir/module.rs
@@ -1,11 +1,17 @@
-use super::adt;
-use crate::ir::dispatch_table::{DispatchTable, DispatchTableBuilder};
-use crate::ir::function;
-use crate::type_info::TypeInfo;
+use crate::ir::{
+ abi_types::gen_abi_types,
+ adt,
+ dispatch_table::{DispatchTable, DispatchTableBuilder},
+ function, intrinsics,
+ type_table::{TypeTable, TypeTableBuilder},
+};
use crate::{CodeGenParams, IrDatabase};
use hir::{FileId, ModuleDef};
-use inkwell::{module::Module, values::FunctionValue};
-use std::collections::{HashMap, HashSet};
+use inkwell::{
+ values::{FunctionValue, UnnamedAddress},
+ AddressSpace,
+};
+use std::collections::{BTreeMap, HashMap};
use std::sync::Arc;
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -13,58 +19,94 @@ pub struct ModuleIR {
/// The original source file
pub file_id: FileId,
- /// The LLVM module that contains the IR
- pub llvm_module: Module,
-
/// A mapping from HIR functions to LLVM IR values
pub functions: HashMap,
- /// A set of unique TypeInfo values
- pub types: HashSet,
-
/// The dispatch table
pub dispatch_table: DispatchTable,
+
+ /// The type table
+ pub type_table: TypeTable,
}
/// Generates IR for the specified file
pub(crate) fn ir_query(db: &impl IrDatabase, file_id: FileId) -> Arc {
- let llvm_module = db
- .context()
- .create_module(db.file_relative_path(file_id).as_str());
+ let llvm_module = db.module();
+ let abi_types = gen_abi_types(llvm_module.get_context());
+
+ // Collect all intrinsic functions and wrapper function.
+ // Use a `BTreeMap` to guarantee deterministically ordered output.
+ let mut intrinsics_map = BTreeMap::new();
+ let mut wrappers = BTreeMap::new();
+ let mut needs_alloc = false;
+ for def in db.module_data(file_id).definitions() {
+ match def {
+ ModuleDef::Function(f) if !f.is_extern(db) => {
+ let fn_sig = f.ty(db).callable_sig(db).unwrap();
+ let body = f.body(db);
+ let infer = f.infer(db);
- // Collect type definitions for all used types
- let mut types = HashSet::new();
+ intrinsics::collect_fn_body(
+ db,
+ &llvm_module,
+ &mut intrinsics_map,
+ &mut needs_alloc,
+ &body,
+ &infer,
+ );
+
+ if !f.data(db).visibility().is_private() && !fn_sig.marshallable(db) {
+ intrinsics::collect_wrapper_body(
+ &llvm_module,
+ &mut intrinsics_map,
+ &mut needs_alloc,
+ );
+
+ // Generate wrapper function
+ let wrapper_fun = function::gen_signature(
+ db,
+ *f,
+ &llvm_module,
+ CodeGenParams {
+ make_marshallable: true,
+ },
+ );
+ wrappers.insert(*f, wrapper_fun);
+ }
+ }
+ ModuleDef::Function(_) => (), // TODO: Extern types?
+ ModuleDef::Struct(_) => (),
+ ModuleDef::BuiltinType(_) => (),
+ }
+ }
+
+ // Collect all used types
+ let mut type_table_builder =
+ TypeTableBuilder::new(db, &llvm_module, &abi_types, intrinsics_map.keys());
for def in db.module_data(file_id).definitions() {
match def {
ModuleDef::Struct(s) => {
- let _t = adt::gen_struct_decl(db, *s);
- types.insert(db.type_info(s.ty(db)));
+ adt::gen_struct_decl(db, *s);
+ type_table_builder.collect_struct(*s);
+ }
+ ModuleDef::Function(f) => {
+ type_table_builder.collect_fn(*f);
}
- ModuleDef::BuiltinType(_) | ModuleDef::Function(_) => (),
+ ModuleDef::BuiltinType(_) => (),
}
}
+ let type_table = type_table_builder.build();
+
// Generate all the function signatures
let mut functions = HashMap::new();
- let mut wrappers = HashMap::new();
- let mut dispatch_table_builder = DispatchTableBuilder::new(db, &llvm_module);
+ let mut dispatch_table_builder = DispatchTableBuilder::new(db, &llvm_module, intrinsics_map);
for def in db.module_data(file_id).definitions() {
// TODO: Remove once we have more ModuleDef variants
#[allow(clippy::single_match)]
match def {
ModuleDef::Function(f) if !f.is_extern(db) => {
- // Collect argument types
- let fn_sig = f.ty(db).callable_sig(db).unwrap();
- for ty in fn_sig.params().iter() {
- types.insert(db.type_info(ty.clone()));
- }
- // Collect return type
- let ret_ty = fn_sig.ret();
- if !ret_ty.is_empty() {
- types.insert(db.type_info(ret_ty.clone()));
- }
-
// Construct the function signature
let fun = function::gen_signature(
db,
@@ -80,21 +122,6 @@ pub(crate) fn ir_query(db: &impl IrDatabase, file_id: FileId) -> Arc {
let body = f.body(db);
let infer = f.infer(db);
dispatch_table_builder.collect_body(&body, &infer);
-
- if f.data(db).visibility() != hir::Visibility::Private && !fn_sig.marshallable(db) {
- let wrapper_fun = function::gen_signature(
- db,
- *f,
- &llvm_module,
- CodeGenParams {
- make_marshallable: true,
- },
- );
- wrappers.insert(*f, wrapper_fun);
-
- // Add calls from the function's wrapper to the dispatch table
- dispatch_table_builder.collect_wrapper_body(*f);
- }
}
_ => {}
}
@@ -104,15 +131,28 @@ pub(crate) fn ir_query(db: &impl IrDatabase, file_id: FileId) -> Arc {
let dispatch_table = dispatch_table_builder.finalize(&functions);
let fn_pass_manager = function::create_pass_manager(&llvm_module, db.optimization_lvl());
+ // Create the allocator handle global value
+ let allocator_handle_global = if needs_alloc {
+ let allocator_handle_global_type = db.context().i8_type().ptr_type(AddressSpace::Generic);
+ let allocator_handle_global =
+ llvm_module.add_global(allocator_handle_global_type, None, "allocatorHandle");
+ allocator_handle_global.set_initializer(&allocator_handle_global_type.const_null());
+ allocator_handle_global.set_linkage(inkwell::module::Linkage::Private);
+ allocator_handle_global.set_unnamed_address(UnnamedAddress::Global);
+ Some(allocator_handle_global)
+ } else {
+ None
+ };
+
// Generate the function bodies
for (hir_function, llvm_function) in functions.iter() {
function::gen_body(
db,
- *hir_function,
- *llvm_function,
- &llvm_module,
+ (*hir_function, *llvm_function),
&functions,
&dispatch_table,
+ &type_table,
+ allocator_handle_global,
);
fn_pass_manager.run_on(llvm_function);
}
@@ -120,27 +160,15 @@ pub(crate) fn ir_query(db: &impl IrDatabase, file_id: FileId) -> Arc {
for (hir_function, llvm_function) in wrappers.iter() {
function::gen_wrapper_body(
db,
- *hir_function,
- *llvm_function,
- &llvm_module,
+ (*hir_function, *llvm_function),
&functions,
&dispatch_table,
+ &type_table,
+ allocator_handle_global,
);
fn_pass_manager.run_on(llvm_function);
}
- // Dispatch entries can include previously unchecked intrinsics
- for entry in dispatch_table.entries().iter() {
- // Collect argument types
- for ty in entry.prototype.arg_types.iter() {
- types.insert(ty.clone());
- }
- // Collect return type
- if let Some(ret_ty) = entry.prototype.ret_type.as_ref() {
- types.insert(ret_ty.clone());
- }
- }
-
// Filter private methods
let mut api: HashMap = functions
.into_iter()
@@ -154,9 +182,8 @@ pub(crate) fn ir_query(db: &impl IrDatabase, file_id: FileId) -> Arc {
Arc::new(ModuleIR {
file_id,
- llvm_module,
functions: api,
- types,
dispatch_table,
+ type_table,
})
}
diff --git a/crates/mun_codegen/src/ir/ty.rs b/crates/mun_codegen/src/ir/ty.rs
index d1f8417e1..5ed9f959c 100644
--- a/crates/mun_codegen/src/ir/ty.rs
+++ b/crates/mun_codegen/src/ir/ty.rs
@@ -56,10 +56,10 @@ pub(crate) fn ir_query(db: &impl IrDatabase, ty: Ty, params: CodeGenParams) -> A
TypeCtor::Struct(s) => {
let struct_ty = db.struct_ty(s);
match s.data(db).memory_kind {
- hir::StructMemoryKind::GC => struct_ty.ptr_type(AddressSpace::Generic).into(),
+ hir::StructMemoryKind::GC => struct_ty.ptr_type(AddressSpace::Const).ptr_type(AddressSpace::Generic).into(),
hir::StructMemoryKind::Value => {
if params.make_marshallable {
- struct_ty.ptr_type(AddressSpace::Generic).into()
+ struct_ty.ptr_type(AddressSpace::Const).ptr_type(AddressSpace::Generic).into()
} else {
struct_ty.into()
}
diff --git a/crates/mun_codegen/src/ir/type_table.rs b/crates/mun_codegen/src/ir/type_table.rs
new file mode 100644
index 000000000..e02b59088
--- /dev/null
+++ b/crates/mun_codegen/src/ir/type_table.rs
@@ -0,0 +1,331 @@
+use crate::code_gen::{
+ gen_global, gen_string_array, gen_struct_ptr_array, gen_u16_array, intern_string,
+};
+use crate::ir::{abi_types::AbiTypes, dispatch_table::FunctionPrototype};
+use crate::type_info::{TypeGroup, TypeInfo};
+use crate::{CodeGenParams, IrDatabase};
+use hir::{Body, ExprId, InferenceResult};
+use inkwell::{
+ module::Module,
+ targets::TargetData,
+ values::{GlobalValue, IntValue, PointerValue, StructValue},
+ AddressSpace,
+};
+use std::collections::{BTreeSet, HashMap};
+use std::{mem, sync::Arc};
+
+/// A type table in IR is a list of pointers to unique type information that are used to generate
+/// function and struct information.
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub struct TypeTable {
+ type_info_to_index: HashMap,
+ entries: Vec,
+ table_ref: PointerValue,
+}
+
+impl TypeTable {
+ /// Generates a `TypeInfo` lookup through the `TypeTable`, equivalent to something along the
+ /// lines of: `type_table[i]`, where `i` is the index of the type and `type_table` is an array
+ /// of `TypeInfo` pointers.
+ pub fn gen_type_info_lookup(
+ &self,
+ builder: &inkwell::builder::Builder,
+ type_info: &TypeInfo,
+ ) -> PointerValue {
+ let index = *self
+ .type_info_to_index
+ .get(type_info)
+ .expect("unknown type");
+
+ let ptr_to_type_info_ptr = unsafe {
+ builder.build_struct_gep(
+ self.table_ref,
+ index as u32,
+ &format!("{}_ptr_ptr", type_info.name),
+ )
+ };
+ builder
+ .build_load(ptr_to_type_info_ptr, &format!("{}_ptr", type_info.name))
+ .into_pointer_value()
+ }
+
+ /// Retrieves the pointer to a `TypeInfo`, if it exists in the `TypeTable`.
+ pub fn get(&self, type_info: &TypeInfo) -> Option {
+ self.type_info_to_index
+ .get(type_info)
+ .map(|index| unsafe { *self.entries.get_unchecked(*index) })
+ }
+
+ /// Returns the number of types in the `TypeTable`.
+ pub fn num_types(&self) -> usize {
+ self.entries.len()
+ }
+
+ /// Returns the value that represents the type table in IR.
+ pub fn pointer_value(&self) -> PointerValue {
+ self.table_ref
+ }
+}
+
+/// Used to build a `TypeTable` from HIR.
+pub(crate) struct TypeTableBuilder<'a, D: IrDatabase> {
+ db: &'a D,
+ target_data: Arc,
+ module: &'a Module,
+ abi_types: &'a AbiTypes,
+ entries: BTreeSet, // Use a `BTreeSet` to guarantee deterministically ordered output
+}
+
+impl<'a, D: IrDatabase> TypeTableBuilder<'a, D> {
+ /// Creates a new `TypeTableBuilder`.
+ pub(crate) fn new<'f>(
+ db: &'a D,
+ module: &'a Module,
+ abi_types: &'a AbiTypes,
+ intrinsics: impl Iterator
- ,
+ ) -> Self {
+ let mut builder = Self {
+ db,
+ target_data: db.target_data(),
+ module,
+ abi_types,
+ entries: BTreeSet::new(),
+ };
+
+ for prototype in intrinsics {
+ for arg_type in prototype.arg_types.iter() {
+ builder.collect_type(arg_type.clone());
+ }
+ if let Some(ret_type) = prototype.ret_type.as_ref() {
+ builder.collect_type(ret_type.clone());
+ }
+ }
+
+ builder
+ }
+
+ /// Collects unique `TypeInfo` from the given `Ty`.
+ fn collect_type(&mut self, type_info: TypeInfo) {
+ if let TypeGroup::StructTypes(hir_struct) = type_info.group {
+ self.collect_struct(hir_struct);
+ } else {
+ self.entries.insert(type_info);
+ }
+ }
+
+ /// Collects unique `TypeInfo` from the specified expression and its sub-expressions.
+ fn collect_expr(&mut self, expr_id: ExprId, body: &Arc, infer: &InferenceResult) {
+ let expr = &body[expr_id];
+
+ // TODO: Collect used external `TypeInfo` for the type dispatch table
+
+ // Recurse further
+ expr.walk_child_exprs(|expr_id| self.collect_expr(expr_id, body, infer))
+ }
+
+ /// Collects unique `TypeInfo` from the specified function signature and body.
+ pub fn collect_fn(&mut self, hir_fn: hir::Function) {
+ // Collect type info for exposed function
+ if !hir_fn.data(self.db).visibility().is_private() {
+ let fn_sig = hir_fn.ty(self.db).callable_sig(self.db).unwrap();
+
+ // Collect argument types
+ for ty in fn_sig.params().iter() {
+ self.collect_type(self.db.type_info(ty.clone()));
+ }
+
+ // Collect return type
+ let ret_ty = fn_sig.ret();
+ if !ret_ty.is_empty() {
+ self.collect_type(self.db.type_info(ret_ty.clone()));
+ }
+ }
+
+ // Collect used types from body
+ let body = hir_fn.body(self.db);
+ let infer = hir_fn.infer(self.db);
+ self.collect_expr(body.body_expr(), &body, &infer);
+ }
+
+ /// Collects unique `TypeInfo` from the specified struct type.
+ pub fn collect_struct(&mut self, hir_struct: hir::Struct) {
+ let type_info = self.db.type_info(hir_struct.ty(self.db));
+ self.entries.insert(type_info);
+
+ let fields = hir_struct.fields(self.db);
+ for field in fields.into_iter() {
+ self.collect_type(self.db.type_info(field.ty(self.db)));
+ }
+ }
+
+ fn gen_type_info(
+ &self,
+ type_info_to_ir: &mut HashMap,
+ type_info: &TypeInfo,
+ ) -> GlobalValue {
+ let context = self.module.get_context();
+ let guid_bytes_ir: [IntValue; 16] = array_init::array_init(|i| {
+ context
+ .i8_type()
+ .const_int(u64::from(type_info.guid.b[i]), false)
+ });
+ let type_info_ir = context.const_struct(
+ &[
+ context.i8_type().const_array(&guid_bytes_ir).into(),
+ intern_string(
+ self.module,
+ &type_info.name,
+ &format!("type_info::<{}>::name", type_info.name),
+ )
+ .into(),
+ context
+ .i8_type()
+ .const_int(type_info.group.clone().into(), false)
+ .into(),
+ ],
+ false,
+ );
+ let type_info_ir = match type_info.group {
+ TypeGroup::FundamentalTypes => type_info_ir,
+ TypeGroup::StructTypes(s) => {
+ let struct_info_ir = self.gen_struct_info(type_info_to_ir, s);
+ context.const_struct(&[type_info_ir.into(), struct_info_ir.into()], false)
+ }
+ };
+ gen_global(
+ self.module,
+ &type_info_ir,
+ &format!("type_info::<{}>", type_info.name),
+ )
+ }
+
+ fn gen_struct_info(
+ &self,
+ type_info_to_ir: &mut HashMap,
+ hir_struct: hir::Struct,
+ ) -> StructValue {
+ let struct_ir = self.db.struct_ty(hir_struct);
+ let fields = hir_struct.fields(self.db);
+
+ let name = hir_struct.name(self.db).to_string();
+ let name_str = intern_string(
+ &self.module,
+ &name,
+ &format!("struct_info::<{}>::name", name),
+ );
+ let field_names = gen_string_array(
+ self.module,
+ fields.iter().map(|field| field.name(self.db).to_string()),
+ &format!("struct_info::<{}>::field_names", name),
+ );
+ let field_types: Vec = fields
+ .iter()
+ .map(|field| {
+ let field_type_info = self.db.type_info(field.ty(self.db));
+ if let Some(ir_value) = type_info_to_ir.get(&field_type_info) {
+ *ir_value
+ } else {
+ let ir_value = self.gen_type_info(type_info_to_ir, &field_type_info);
+ type_info_to_ir.insert(field_type_info, ir_value);
+ ir_value
+ }
+ .as_pointer_value()
+ })
+ .collect();
+
+ let field_types = gen_struct_ptr_array(
+ self.module,
+ self.abi_types.type_info_type,
+ &field_types,
+ &format!("struct_info::<{}>::field_types", name),
+ );
+
+ let field_offsets = gen_u16_array(
+ self.module,
+ (0..fields.len()).map(|idx| {
+ self.target_data
+ .offset_of_element(&struct_ir, idx as u32)
+ .unwrap()
+ }),
+ );
+ let field_sizes = gen_u16_array(
+ self.module,
+ fields.iter().map(|field| {
+ self.target_data.get_store_size(&self.db.type_ir(
+ field.ty(self.db),
+ CodeGenParams {
+ make_marshallable: false,
+ },
+ ))
+ }),
+ );
+
+ let alignment = self.target_data.get_abi_alignment(&struct_ir);
+
+ self.abi_types.struct_info_type.const_named_struct(&[
+ name_str.into(),
+ field_names.into(),
+ field_types.into(),
+ field_offsets.into(),
+ field_sizes.into(),
+ self.module
+ .get_context()
+ .i16_type()
+ .const_int(fields.len() as u64, false)
+ .into(),
+ self.module
+ .get_context()
+ .i16_type()
+ .const_int(alignment.into(), false)
+ .into(),
+ self.module
+ .get_context()
+ .i8_type()
+ .const_int(hir_struct.data(self.db).memory_kind.clone().into(), false)
+ .into(),
+ ])
+ }
+
+ /// Constructs a `TypeTable` from all *used* types.
+ pub fn build(mut self) -> TypeTable {
+ let mut entries = BTreeSet::new();
+ mem::swap(&mut entries, &mut self.entries);
+
+ let mut type_info_to_ir = HashMap::with_capacity(entries.len());
+ let mut type_info_to_index = HashMap::with_capacity(entries.len());
+
+ let type_info_ptrs: Vec = entries
+ .into_iter()
+ .enumerate()
+ .map(|(index, type_info)| {
+ let ptr = if let Some(ir_value) = type_info_to_ir.get(&type_info) {
+ *ir_value
+ } else {
+ let ir_value = self.gen_type_info(&mut type_info_to_ir, &type_info);
+ type_info_to_ir.insert(type_info.clone(), ir_value);
+ ir_value
+ }
+ .as_pointer_value();
+
+ type_info_to_index.insert(type_info, index);
+ ptr
+ })
+ .collect();
+
+ let type_info_ptr_type = self.abi_types.type_info_type.ptr_type(AddressSpace::Const);
+ let global_type_info_array = if type_info_ptrs.is_empty() {
+ type_info_ptr_type
+ .ptr_type(AddressSpace::Const)
+ .const_null()
+ } else {
+ let type_info_ptrs_array = type_info_ptr_type.const_array(&type_info_ptrs);
+ gen_global(self.module, &type_info_ptrs_array, "global_type_table").as_pointer_value()
+ };
+
+ TypeTable {
+ type_info_to_index,
+ entries: type_info_ptrs,
+ table_ref: global_type_info_array,
+ }
+ }
+}
diff --git a/crates/mun_codegen/src/lib.rs b/crates/mun_codegen/src/lib.rs
index 69bb77bf6..b9cf8cf18 100644
--- a/crates/mun_codegen/src/lib.rs
+++ b/crates/mun_codegen/src/lib.rs
@@ -3,7 +3,6 @@ mod code_gen;
mod db;
#[macro_use]
mod ir;
-pub(crate) mod symbols;
#[cfg(test)]
mod mock;
@@ -16,7 +15,7 @@ pub(crate) mod type_info;
pub use inkwell::{builder, context::Context, module::Module, values, OptimizationLevel};
pub use crate::{
- code_gen::write_module_shared_object,
+ code_gen::ModuleBuilder,
db::{IrDatabase, IrDatabaseStorage},
};
diff --git a/crates/mun_codegen/src/snapshots/test__binary_expressions.snap b/crates/mun_codegen/src/snapshots/test__binary_expressions.snap
index b6a85560a..c26d75410 100644
--- a/crates/mun_codegen/src/snapshots/test__binary_expressions.snap
+++ b/crates/mun_codegen/src/snapshots/test__binary_expressions.snap
@@ -4,6 +4,7 @@ expression: "fn add(a:int, b:int):int {\n a+b\n}\n\nfn subtract(a:int, b:int):i
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i64 @add(i64, i64) {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__conditional_return_expr.snap b/crates/mun_codegen/src/snapshots/test__conditional_return_expr.snap
index fe7edca9c..156e39a1d 100644
--- a/crates/mun_codegen/src/snapshots/test__conditional_return_expr.snap
+++ b/crates/mun_codegen/src/snapshots/test__conditional_return_expr.snap
@@ -4,6 +4,7 @@ expression: "fn main(a:int):int {\n if a > 4 {\n return a;\n }\n
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i64 @main(i64) {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__equality_operands.snap b/crates/mun_codegen/src/snapshots/test__equality_operands.snap
index e1df58b00..f7f0102d0 100644
--- a/crates/mun_codegen/src/snapshots/test__equality_operands.snap
+++ b/crates/mun_codegen/src/snapshots/test__equality_operands.snap
@@ -4,6 +4,7 @@ expression: "fn equals(a:int, b:int):bool { a == b }\nfn not_equa
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i1 @equals(i64, i64) {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__extern_fn.snap b/crates/mun_codegen/src/snapshots/test__extern_fn.snap
index 3cfd0445e..249c91654 100644
--- a/crates/mun_codegen/src/snapshots/test__extern_fn.snap
+++ b/crates/mun_codegen/src/snapshots/test__extern_fn.snap
@@ -4,6 +4,7 @@ expression: "extern fn add(a:int, b:int): int;\nfn main() {\n add(3,4);\n}"
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
%DispatchTable = type { i64 (i64, i64)* }
diff --git a/crates/mun_codegen/src/snapshots/test__fibonacci.snap b/crates/mun_codegen/src/snapshots/test__fibonacci.snap
index 05bd5a0b4..d70e1e7df 100644
--- a/crates/mun_codegen/src/snapshots/test__fibonacci.snap
+++ b/crates/mun_codegen/src/snapshots/test__fibonacci.snap
@@ -4,6 +4,7 @@ expression: "fn fibonacci(n:int):int {\n if n <= 1 {\n n\n } else {
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
%DispatchTable = type { i64 (i64)* }
diff --git a/crates/mun_codegen/src/snapshots/test__fibonacci_loop.snap b/crates/mun_codegen/src/snapshots/test__fibonacci_loop.snap
index a19d6ece6..03c5a9369 100644
--- a/crates/mun_codegen/src/snapshots/test__fibonacci_loop.snap
+++ b/crates/mun_codegen/src/snapshots/test__fibonacci_loop.snap
@@ -4,6 +4,7 @@ expression: "fn fibonacci(n:int):int {\n let a = 0;\n let b = 1;\n let
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i64 @fibonacci(i64) {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__field_crash.snap b/crates/mun_codegen/src/snapshots/test__field_crash.snap
index 5cf383f7e..54decfdd9 100644
--- a/crates/mun_codegen/src/snapshots/test__field_crash.snap
+++ b/crates/mun_codegen/src/snapshots/test__field_crash.snap
@@ -4,28 +4,56 @@ expression: "struct(gc) Foo { a: int };\n\nfn main(c:int):int {\n let b = Foo
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
-%DispatchTable = type { i8* (i8 addrspace(4)*, i8 addrspace(4)*)*, i8* (i64, i64)* }
+%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i8 }
+%struct.MunStructInfo = type { i8 addrspace(4)*, i8 addrspace(4)* addrspace(4)*, %struct.MunTypeInfo addrspace(4)* addrspace(4)*, i16 addrspace(4)*, i16 addrspace(4)*, i16, i16, i8 }
+%DispatchTable = type { i8* addrspace(4)* (i8 addrspace(4)*, i8*)*, i8* addrspace(4)* (i8 addrspace(4)*, i8*)* }
%Foo = type { i64 }
+@"type_info::::name" = private unnamed_addr constant [4 x i8] c"Foo\00"
+@"struct_info::::name" = private unnamed_addr constant [4 x i8] c"Foo\00"
+@"struct_info::::field_names" = private unnamed_addr constant [2 x i8] c"a\00"
+@0 = private unnamed_addr constant [1 x i8 addrspace(4)*] [i8 addrspace(4)* @"struct_info::::field_names"]
+@"type_info::::name" = private unnamed_addr constant [10 x i8] c"core::i64\00"
+@"type_info::" = private unnamed_addr constant { [16 x i8], [10 x i8]*, i8 } { [16 x i8] c"G\13;t\97j8\18\D7M\83`\1D\C8\19%", [10 x i8]* @"type_info::::name", i8 0 }
+@"struct_info::::field_types" = private unnamed_addr constant [1 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::"]
+@1 = private unnamed_addr constant [1 x i16] zeroinitializer
+@2 = private unnamed_addr constant [1 x i16] [i16 8]
+@"type_info::" = private unnamed_addr constant { { [16 x i8], [4 x i8]*, i8 }, %struct.MunStructInfo } { { [16 x i8], [4 x i8]*, i8 } { [16 x i8] c"\13V\C6}z\D1c\8D\81k\FB\82-\D2\C2]", [4 x i8]* @"type_info::::name", i8 1 }, %struct.MunStructInfo { [4 x i8]* @"struct_info::::name", [1 x i8 addrspace(4)*]* @0, [1 x %struct.MunTypeInfo addrspace(4)*]* @"struct_info::::field_types", [1 x i16]* @1, [1 x i16]* @2, i16 1, i16 8, i8 0 } }
+@"type_info::<*const TypeInfo>::name" = private unnamed_addr constant [16 x i8] c"*const TypeInfo\00"
+@"type_info::<*const TypeInfo>" = private unnamed_addr constant { [16 x i8], [16 x i8]*, i8 } { [16 x i8] c"=\A1-\1F\C2\A7\88`d\90\F4\B5\BEE}x", [16 x i8]* @"type_info::<*const TypeInfo>::name", i8 0 }
+@"type_info::<*const *mut core::void>::name" = private unnamed_addr constant [23 x i8] c"*const *mut core::void\00"
+@"type_info::<*const *mut core::void>" = private unnamed_addr constant { [16 x i8], [23 x i8]*, i8 } { [16 x i8] c"\C5fO\BD\84\DF\06\BFd+\B1\9Abv\CE\00", [23 x i8]* @"type_info::<*const *mut core::void>::name", i8 0 }
+@"type_info::<*const core::void>::name" = private unnamed_addr constant [18 x i8] c"*const core::void\00"
+@"type_info::<*const core::void>" = private unnamed_addr constant { [16 x i8], [18 x i8]*, i8 } { [16 x i8] c"\EF\D3\E0ac~\5C\D4\EF\AE\B1}\CA\BE\DA\16", [18 x i8]* @"type_info::<*const core::void>::name", i8 0 }
+@"type_info::<*mut core::void>::name" = private unnamed_addr constant [16 x i8] c"*mut core::void\00"
+@"type_info::<*mut core::void>" = private unnamed_addr constant { [16 x i8], [16 x i8]*, i8 } { [16 x i8] c"\F0Y\22\FC\95\9E\7F\CE\08T\B1\A2\CD\A7\FAz", [16 x i8]* @"type_info::<*mut core::void>::name", i8 0 }
+@global_type_table = private unnamed_addr constant [6 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::<*const TypeInfo>", %struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::<*const *mut core::void>", %struct.MunTypeInfo addrspace(4)* @"type_info::<*const core::void>", %struct.MunTypeInfo addrspace(4)* @"type_info::<*mut core::void>"]
@dispatchTable = global %DispatchTable zeroinitializer
+@allocatorHandle = private unnamed_addr global i8* null
define i64 @main(i64) {
body:
- %b = alloca %Foo*
+ %b = alloca %Foo addrspace(4)**
%c = alloca i64
store i64 %0, i64* %c
%c1 = load i64, i64* %c
%add = add i64 %c1, 5
%init = insertvalue %Foo undef, i64 %add, 0
- %malloc_ptr = load i8* (i64, i64)*, i8* (i64, i64)** getelementptr inbounds (%DispatchTable, %DispatchTable* @dispatchTable, i32 0, i32 1)
- %malloc = call i8* %malloc_ptr(i64 ptrtoint (i64* getelementptr (i64, i64* null, i32 1) to i64), i64 ptrtoint (i64* getelementptr ({ i1, i64 }, { i1, i64 }* null, i64 0, i32 1) to i64))
- %Foo = bitcast i8* %malloc to %Foo*
+ %new_ptr = load i8* addrspace(4)* (i8 addrspace(4)*, i8*)*, i8* addrspace(4)* (i8 addrspace(4)*, i8*)** getelementptr inbounds (%DispatchTable, %DispatchTable* @dispatchTable, i32 0, i32 1)
+ %Foo_ptr = load %struct.MunTypeInfo addrspace(4)*, %struct.MunTypeInfo addrspace(4)** getelementptr inbounds ([6 x %struct.MunTypeInfo addrspace(4)*], [6 x %struct.MunTypeInfo addrspace(4)*]* @global_type_table, i32 0, i32 0)
+ %type_info_ptr_to_i8_ptr = bitcast %struct.MunTypeInfo addrspace(4)* %Foo_ptr to i8 addrspace(4)*
+ %allocator_handle = load i8*, i8** @allocatorHandle
+ %new = call i8* addrspace(4)* %new_ptr(i8 addrspace(4)* %type_info_ptr_to_i8_ptr, i8* %allocator_handle)
+ %mem_ptr = load i8*, i8* addrspace(4)* %new
+ %Foo = bitcast i8* %mem_ptr to %Foo*
store %Foo %init, %Foo* %Foo
- store %Foo* %Foo, %Foo** %b
- %deref = load %Foo*, %Foo** %b
- %Foo.a = getelementptr inbounds %Foo, %Foo* %deref, i32 0, i32 0
- %a = load i64, i64* %Foo.a
+ store i8* addrspace(4)* %new, %Foo addrspace(4)*** %b
+ %mem_ptr2 = load %Foo addrspace(4)**, %Foo addrspace(4)*** %b
+ %deref = load %Foo addrspace(4)*, %Foo addrspace(4)** %mem_ptr2
+ %Foo.a = getelementptr inbounds %Foo, %Foo addrspace(4)* %deref, i32 0, i32 0
+ %a = load i64, i64 addrspace(4)* %Foo.a
ret i64 %a
}
diff --git a/crates/mun_codegen/src/snapshots/test__field_expr.snap b/crates/mun_codegen/src/snapshots/test__field_expr.snap
index 9f8ea630d..e0b8b62cf 100644
--- a/crates/mun_codegen/src/snapshots/test__field_expr.snap
+++ b/crates/mun_codegen/src/snapshots/test__field_expr.snap
@@ -4,12 +4,46 @@ expression: "struct(value) Bar(float, Foo);\nstruct(value) Foo { a: int };\n\nfn
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
-%DispatchTable = type { i64 (%Foo)*, %Foo (%Bar)*, i8* (i8 addrspace(4)*, i8 addrspace(4)*)* }
+%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i8 }
+%struct.MunStructInfo = type { i8 addrspace(4)*, i8 addrspace(4)* addrspace(4)*, %struct.MunTypeInfo addrspace(4)* addrspace(4)*, i16 addrspace(4)*, i16 addrspace(4)*, i16, i16, i8 }
+%DispatchTable = type { i8* addrspace(4)* (i8 addrspace(4)*, i8*)*, i8* addrspace(4)* (i8 addrspace(4)*, i8*)*, i64 (%Foo)*, %Foo (%Bar)* }
%Foo = type { i64 }
%Bar = type { double, %Foo }
-@dispatchTable = global %DispatchTable { i64 (%Foo)* @foo_a, %Foo (%Bar)* @bar_1, i8* (i8 addrspace(4)*, i8 addrspace(4)*)* null }
+@"type_info::::name" = private unnamed_addr constant [4 x i8] c"Foo\00"
+@"struct_info::::name" = private unnamed_addr constant [4 x i8] c"Foo\00"
+@"struct_info::::field_names" = private unnamed_addr constant [2 x i8] c"a\00"
+@0 = private unnamed_addr constant [1 x i8 addrspace(4)*] [i8 addrspace(4)* @"struct_info::::field_names"]
+@"type_info::::name" = private unnamed_addr constant [10 x i8] c"core::i64\00"
+@"type_info::" = private unnamed_addr constant { [16 x i8], [10 x i8]*, i8 } { [16 x i8] c"G\13;t\97j8\18\D7M\83`\1D\C8\19%", [10 x i8]* @"type_info::::name", i8 0 }
+@"struct_info::::field_types" = private unnamed_addr constant [1 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::"]
+@1 = private unnamed_addr constant [1 x i16] zeroinitializer
+@2 = private unnamed_addr constant [1 x i16] [i16 8]
+@"type_info::" = private unnamed_addr constant { { [16 x i8], [4 x i8]*, i8 }, %struct.MunStructInfo } { { [16 x i8], [4 x i8]*, i8 } { [16 x i8] c"\13V\C6}z\D1c\8D\81k\FB\82-\D2\C2]", [4 x i8]* @"type_info::::name", i8 1 }, %struct.MunStructInfo { [4 x i8]* @"struct_info::::name", [1 x i8 addrspace(4)*]* @0, [1 x %struct.MunTypeInfo addrspace(4)*]* @"struct_info::::field_types", [1 x i16]* @1, [1 x i16]* @2, i16 1, i16 8, i8 1 } }
+@"type_info::<*const TypeInfo>::name" = private unnamed_addr constant [16 x i8] c"*const TypeInfo\00"
+@"type_info::<*const TypeInfo>" = private unnamed_addr constant { [16 x i8], [16 x i8]*, i8 } { [16 x i8] c"=\A1-\1F\C2\A7\88`d\90\F4\B5\BEE}x", [16 x i8]* @"type_info::<*const TypeInfo>::name", i8 0 }
+@"type_info::::name" = private unnamed_addr constant [10 x i8] c"core::f64\00"
+@"type_info::" = private unnamed_addr constant { [16 x i8], [10 x i8]*, i8 } { [16 x i8] c"`\DBF\9C?YJ%G\AD4\9F\D5\92%A", [10 x i8]* @"type_info::::name", i8 0 }
+@"type_info::<*const *mut core::void>::name" = private unnamed_addr constant [23 x i8] c"*const *mut core::void\00"
+@"type_info::<*const *mut core::void>" = private unnamed_addr constant { [16 x i8], [23 x i8]*, i8 } { [16 x i8] c"\C5fO\BD\84\DF\06\BFd+\B1\9Abv\CE\00", [23 x i8]* @"type_info::<*const *mut core::void>::name", i8 0 }
+@"type_info::::name" = private unnamed_addr constant [4 x i8] c"Bar\00"
+@"struct_info::::name" = private unnamed_addr constant [4 x i8] c"Bar\00"
+@"struct_info::::field_names" = private unnamed_addr constant [2 x i8] c"0\00"
+@"struct_info::::field_names.1" = private unnamed_addr constant [2 x i8] c"1\00"
+@3 = private unnamed_addr constant [2 x i8 addrspace(4)*] [i8 addrspace(4)* @"struct_info::::field_names", i8 addrspace(4)* @"struct_info::::field_names.1"]
+@"struct_info::::field_types" = private unnamed_addr constant [2 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::"]
+@4 = private unnamed_addr constant [2 x i16] [i16 0, i16 8]
+@5 = private unnamed_addr constant [2 x i16] [i16 8, i16 8]
+@"type_info::" = private unnamed_addr constant { { [16 x i8], [4 x i8]*, i8 }, %struct.MunStructInfo } { { [16 x i8], [4 x i8]*, i8 } { [16 x i8] c"\DD\C3_\88\FAq\B6\EF\14*\E6\1F56FS", [4 x i8]* @"type_info::::name", i8 1 }, %struct.MunStructInfo { [4 x i8]* @"struct_info::::name", [2 x i8 addrspace(4)*]* @3, [2 x %struct.MunTypeInfo addrspace(4)*]* @"struct_info::::field_types", [2 x i16]* @4, [2 x i16]* @5, i16 2, i16 8, i8 1 } }
+@"type_info::<*const core::void>::name" = private unnamed_addr constant [18 x i8] c"*const core::void\00"
+@"type_info::<*const core::void>" = private unnamed_addr constant { [16 x i8], [18 x i8]*, i8 } { [16 x i8] c"\EF\D3\E0ac~\5C\D4\EF\AE\B1}\CA\BE\DA\16", [18 x i8]* @"type_info::<*const core::void>::name", i8 0 }
+@"type_info::<*mut core::void>::name" = private unnamed_addr constant [16 x i8] c"*mut core::void\00"
+@"type_info::<*mut core::void>" = private unnamed_addr constant { [16 x i8], [16 x i8]*, i8 } { [16 x i8] c"\F0Y\22\FC\95\9E\7F\CE\08T\B1\A2\CD\A7\FAz", [16 x i8]* @"type_info::<*mut core::void>::name", i8 0 }
+@global_type_table = private unnamed_addr constant [8 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::<*const TypeInfo>", %struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::<*const *mut core::void>", %struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::<*const core::void>", %struct.MunTypeInfo addrspace(4)* @"type_info::<*mut core::void>"]
+@dispatchTable = global %DispatchTable { i8* addrspace(4)* (i8 addrspace(4)*, i8*)* null, i8* addrspace(4)* (i8 addrspace(4)*, i8*)* null, i64 (%Foo)* @foo_a, %Foo (%Bar)* @bar_1 }
+@allocatorHandle = private unnamed_addr global i8* null
define double @bar_0(%Bar) {
body:
@@ -40,9 +74,9 @@ define i64 @bar_1_foo_a(%Bar) {
body:
%.fca.0.extract = extractvalue %Bar %0, 0
%.fca.1.0.extract = extractvalue %Bar %0, 1, 0
- %bar_1_ptr = load %Foo (%Bar)*, %Foo (%Bar)** getelementptr inbounds (%DispatchTable, %DispatchTable* @dispatchTable, i32 0, i32 1)
+ %bar_1_ptr = load %Foo (%Bar)*, %Foo (%Bar)** getelementptr inbounds (%DispatchTable, %DispatchTable* @dispatchTable, i32 0, i32 3)
%bar_1 = call %Foo %bar_1_ptr(%Bar %0)
- %foo_a_ptr = load i64 (%Foo)*, i64 (%Foo)** getelementptr inbounds (%DispatchTable, %DispatchTable* @dispatchTable, i32 0, i32 0)
+ %foo_a_ptr = load i64 (%Foo)*, i64 (%Foo)** getelementptr inbounds (%DispatchTable, %DispatchTable* @dispatchTable, i32 0, i32 2)
%foo_a = call i64 %foo_a_ptr(%Foo %bar_1)
ret i64 %foo_a
}
diff --git a/crates/mun_codegen/src/snapshots/test__function.snap b/crates/mun_codegen/src/snapshots/test__function.snap
index 28335de17..d6ff392b7 100644
--- a/crates/mun_codegen/src/snapshots/test__function.snap
+++ b/crates/mun_codegen/src/snapshots/test__function.snap
@@ -4,6 +4,7 @@ expression: "fn main() {\n}"
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define void @main() {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__function_arguments.snap b/crates/mun_codegen/src/snapshots/test__function_arguments.snap
index 1918d91d5..a32c3c6eb 100644
--- a/crates/mun_codegen/src/snapshots/test__function_arguments.snap
+++ b/crates/mun_codegen/src/snapshots/test__function_arguments.snap
@@ -4,6 +4,7 @@ expression: "fn main(a:int):int {\n a\n}"
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i64 @main(i64) {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__function_calls.snap b/crates/mun_codegen/src/snapshots/test__function_calls.snap
index 4fa5b53b7..eac7ed95e 100644
--- a/crates/mun_codegen/src/snapshots/test__function_calls.snap
+++ b/crates/mun_codegen/src/snapshots/test__function_calls.snap
@@ -4,6 +4,7 @@ expression: "fn add_impl(a:int, b:int):int {\n a+b\n}\n\nfn add(a:int, b:int)
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
%DispatchTable = type { i64 (i64, i64)*, i64 (i64, i64)* }
diff --git a/crates/mun_codegen/src/snapshots/test__gc_struct.snap b/crates/mun_codegen/src/snapshots/test__gc_struct.snap
index 0806e5f06..911ef8dde 100644
--- a/crates/mun_codegen/src/snapshots/test__gc_struct.snap
+++ b/crates/mun_codegen/src/snapshots/test__gc_struct.snap
@@ -4,30 +4,60 @@ expression: "struct(gc) Foo { a: int, b: int };\n\nfn foo() {\n let a = Foo {
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
-%DispatchTable = type { i8* (i8 addrspace(4)*, i8 addrspace(4)*)*, i8* (i64, i64)* }
+%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i8 }
+%struct.MunStructInfo = type { i8 addrspace(4)*, i8 addrspace(4)* addrspace(4)*, %struct.MunTypeInfo addrspace(4)* addrspace(4)*, i16 addrspace(4)*, i16 addrspace(4)*, i16, i16, i8 }
+%DispatchTable = type { i8* addrspace(4)* (i8 addrspace(4)*, i8*)*, i8* addrspace(4)* (i8 addrspace(4)*, i8*)* }
%Foo = type { i64, i64 }
+@"type_info::::name" = private unnamed_addr constant [4 x i8] c"Foo\00"
+@"struct_info::::name" = private unnamed_addr constant [4 x i8] c"Foo\00"
+@"struct_info::::field_names" = private unnamed_addr constant [2 x i8] c"a\00"
+@"struct_info::::field_names.1" = private unnamed_addr constant [2 x i8] c"b\00"
+@0 = private unnamed_addr constant [2 x i8 addrspace(4)*] [i8 addrspace(4)* @"struct_info::::field_names", i8 addrspace(4)* @"struct_info::::field_names.1"]
+@"type_info::::name" = private unnamed_addr constant [10 x i8] c"core::i64\00"
+@"type_info::" = private unnamed_addr constant { [16 x i8], [10 x i8]*, i8 } { [16 x i8] c"G\13;t\97j8\18\D7M\83`\1D\C8\19%", [10 x i8]* @"type_info::::name", i8 0 }
+@"struct_info::::field_types" = private unnamed_addr constant [2 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::"]
+@1 = private unnamed_addr constant [2 x i16] [i16 0, i16 8]
+@2 = private unnamed_addr constant [2 x i16] [i16 8, i16 8]
+@"type_info::" = private unnamed_addr constant { { [16 x i8], [4 x i8]*, i8 }, %struct.MunStructInfo } { { [16 x i8], [4 x i8]*, i8 } { [16 x i8] c"\13V\C6}z\D1c\8D\81k\FB\82-\D2\C2]", [4 x i8]* @"type_info::::name", i8 1 }, %struct.MunStructInfo { [4 x i8]* @"struct_info::::name", [2 x i8 addrspace(4)*]* @0, [2 x %struct.MunTypeInfo addrspace(4)*]* @"struct_info::::field_types", [2 x i16]* @1, [2 x i16]* @2, i16 2, i16 8, i8 0 } }
+@"type_info::<*const TypeInfo>::name" = private unnamed_addr constant [16 x i8] c"*const TypeInfo\00"
+@"type_info::<*const TypeInfo>" = private unnamed_addr constant { [16 x i8], [16 x i8]*, i8 } { [16 x i8] c"=\A1-\1F\C2\A7\88`d\90\F4\B5\BEE}x", [16 x i8]* @"type_info::<*const TypeInfo>::name", i8 0 }
+@"type_info::<*const *mut core::void>::name" = private unnamed_addr constant [23 x i8] c"*const *mut core::void\00"
+@"type_info::<*const *mut core::void>" = private unnamed_addr constant { [16 x i8], [23 x i8]*, i8 } { [16 x i8] c"\C5fO\BD\84\DF\06\BFd+\B1\9Abv\CE\00", [23 x i8]* @"type_info::<*const *mut core::void>::name", i8 0 }
+@"type_info::<*const core::void>::name" = private unnamed_addr constant [18 x i8] c"*const core::void\00"
+@"type_info::<*const core::void>" = private unnamed_addr constant { [16 x i8], [18 x i8]*, i8 } { [16 x i8] c"\EF\D3\E0ac~\5C\D4\EF\AE\B1}\CA\BE\DA\16", [18 x i8]* @"type_info::<*const core::void>::name", i8 0 }
+@"type_info::<*mut core::void>::name" = private unnamed_addr constant [16 x i8] c"*mut core::void\00"
+@"type_info::<*mut core::void>" = private unnamed_addr constant { [16 x i8], [16 x i8]*, i8 } { [16 x i8] c"\F0Y\22\FC\95\9E\7F\CE\08T\B1\A2\CD\A7\FAz", [16 x i8]* @"type_info::<*mut core::void>::name", i8 0 }
+@global_type_table = private unnamed_addr constant [6 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::<*const TypeInfo>", %struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::<*const *mut core::void>", %struct.MunTypeInfo addrspace(4)* @"type_info::<*const core::void>", %struct.MunTypeInfo addrspace(4)* @"type_info::<*mut core::void>"]
@dispatchTable = global %DispatchTable zeroinitializer
+@allocatorHandle = private unnamed_addr global i8* null
define void @foo() {
body:
- %b4 = alloca %Foo*
- %a = alloca %Foo*
- %malloc_ptr = load i8* (i64, i64)*, i8* (i64, i64)** getelementptr inbounds (%DispatchTable, %DispatchTable* @dispatchTable, i32 0, i32 1)
- %malloc = call i8* %malloc_ptr(i64 mul nuw (i64 ptrtoint (i64* getelementptr (i64, i64* null, i32 1) to i64), i64 2), i64 ptrtoint (i64* getelementptr ({ i1, i64 }, { i1, i64 }* null, i64 0, i32 1) to i64))
- %Foo = bitcast i8* %malloc to %Foo*
+ %b6 = alloca %Foo addrspace(4)**
+ %a = alloca %Foo addrspace(4)**
+ %new_ptr = load i8* addrspace(4)* (i8 addrspace(4)*, i8*)*, i8* addrspace(4)* (i8 addrspace(4)*, i8*)** getelementptr inbounds (%DispatchTable, %DispatchTable* @dispatchTable, i32 0, i32 1)
+ %Foo_ptr = load %struct.MunTypeInfo addrspace(4)*, %struct.MunTypeInfo addrspace(4)** getelementptr inbounds ([6 x %struct.MunTypeInfo addrspace(4)*], [6 x %struct.MunTypeInfo addrspace(4)*]* @global_type_table, i32 0, i32 0)
+ %type_info_ptr_to_i8_ptr = bitcast %struct.MunTypeInfo addrspace(4)* %Foo_ptr to i8 addrspace(4)*
+ %allocator_handle = load i8*, i8** @allocatorHandle
+ %new = call i8* addrspace(4)* %new_ptr(i8 addrspace(4)* %type_info_ptr_to_i8_ptr, i8* %allocator_handle)
+ %mem_ptr = load i8*, i8* addrspace(4)* %new
+ %Foo = bitcast i8* %mem_ptr to %Foo*
store %Foo { i64 3, i64 4 }, %Foo* %Foo
- store %Foo* %Foo, %Foo** %a
- %deref = load %Foo*, %Foo** %a
- %Foo.b = getelementptr inbounds %Foo, %Foo* %deref, i32 0, i32 1
- %b = load i64, i64* %Foo.b
+ store i8* addrspace(4)* %new, %Foo addrspace(4)*** %a
+ %mem_ptr1 = load %Foo addrspace(4)**, %Foo addrspace(4)*** %a
+ %deref = load %Foo addrspace(4)*, %Foo addrspace(4)** %mem_ptr1
+ %Foo.b = getelementptr inbounds %Foo, %Foo addrspace(4)* %deref, i32 0, i32 1
+ %b = load i64, i64 addrspace(4)* %Foo.b
%add = add i64 %b, 3
- %deref1 = load %Foo*, %Foo** %a
- %Foo.b2 = getelementptr inbounds %Foo, %Foo* %deref1, i32 0, i32 1
- store i64 %add, i64* %Foo.b2
- %a3 = load %Foo*, %Foo** %a
- store %Foo* %a3, %Foo** %b4
+ %mem_ptr2 = load %Foo addrspace(4)**, %Foo addrspace(4)*** %a
+ %deref3 = load %Foo addrspace(4)*, %Foo addrspace(4)** %mem_ptr2
+ %Foo.b4 = getelementptr inbounds %Foo, %Foo addrspace(4)* %deref3, i32 0, i32 1
+ store i64 %add, i64 addrspace(4)* %Foo.b4
+ %a5 = load %Foo addrspace(4)**, %Foo addrspace(4)*** %a
+ store %Foo addrspace(4)** %a5, %Foo addrspace(4)*** %b6
ret void
}
diff --git a/crates/mun_codegen/src/snapshots/test__if_statement.snap b/crates/mun_codegen/src/snapshots/test__if_statement.snap
index 701abafb2..17cbf1db3 100644
--- a/crates/mun_codegen/src/snapshots/test__if_statement.snap
+++ b/crates/mun_codegen/src/snapshots/test__if_statement.snap
@@ -4,6 +4,7 @@ expression: "fn foo(a:int):int {\n let b = if a > 3 {\n let c = if a >
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i64 @foo(i64) {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__let_statement.snap b/crates/mun_codegen/src/snapshots/test__let_statement.snap
index ff5330f63..5440c910b 100644
--- a/crates/mun_codegen/src/snapshots/test__let_statement.snap
+++ b/crates/mun_codegen/src/snapshots/test__let_statement.snap
@@ -4,6 +4,7 @@ expression: "fn main(a:int):int {\n let b = a+1\n b\n}"
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i64 @main(i64) {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__loop_break_expr.snap b/crates/mun_codegen/src/snapshots/test__loop_break_expr.snap
index d6e3e9909..36d120376 100644
--- a/crates/mun_codegen/src/snapshots/test__loop_break_expr.snap
+++ b/crates/mun_codegen/src/snapshots/test__loop_break_expr.snap
@@ -4,6 +4,7 @@ expression: "fn foo(n:int):int {\n loop {\n if n > 5 {\n br
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i64 @foo(i64) {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__loop_expr.snap b/crates/mun_codegen/src/snapshots/test__loop_expr.snap
index 44f2f7c3a..fe138bc30 100644
--- a/crates/mun_codegen/src/snapshots/test__loop_expr.snap
+++ b/crates/mun_codegen/src/snapshots/test__loop_expr.snap
@@ -4,6 +4,7 @@ expression: "fn foo() {\n loop {}\n}"
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define void @foo() {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__never_conditional_return_expr.snap b/crates/mun_codegen/src/snapshots/test__never_conditional_return_expr.snap
index 34a8a1f49..920f568c4 100644
--- a/crates/mun_codegen/src/snapshots/test__never_conditional_return_expr.snap
+++ b/crates/mun_codegen/src/snapshots/test__never_conditional_return_expr.snap
@@ -4,6 +4,7 @@ expression: "fn main(a:int):int {\n if a > 4 {\n return a;\n } else
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i64 @main(i64) {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__primitive_types.snap b/crates/mun_codegen/src/snapshots/test__primitive_types.snap
index a835baffd..b5fd2c72b 100644
--- a/crates/mun_codegen/src/snapshots/test__primitive_types.snap
+++ b/crates/mun_codegen/src/snapshots/test__primitive_types.snap
@@ -4,6 +4,7 @@ expression: "fn add(a: u8, b: u8): u8 { a+b }\n fn less(a: u16, b: u16): bool
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i8 @add(i8, i8) {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__return_expr.snap b/crates/mun_codegen/src/snapshots/test__return_expr.snap
index 552f2cdec..058a4b863 100644
--- a/crates/mun_codegen/src/snapshots/test__return_expr.snap
+++ b/crates/mun_codegen/src/snapshots/test__return_expr.snap
@@ -4,6 +4,7 @@ expression: "fn main():int {\n return 5;\n let a = 3; // Nothing regarding
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i64 @main() {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__return_type.snap b/crates/mun_codegen/src/snapshots/test__return_type.snap
index 4ce17d4d7..5c42186f3 100644
--- a/crates/mun_codegen/src/snapshots/test__return_type.snap
+++ b/crates/mun_codegen/src/snapshots/test__return_type.snap
@@ -4,6 +4,7 @@ expression: "fn main():int {\n 0\n}"
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i64 @main() {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__shadowing.snap b/crates/mun_codegen/src/snapshots/test__shadowing.snap
index 28bbb04a8..9604803e6 100644
--- a/crates/mun_codegen/src/snapshots/test__shadowing.snap
+++ b/crates/mun_codegen/src/snapshots/test__shadowing.snap
@@ -4,6 +4,7 @@ expression: "fn foo(a:int):int {\n let a = a+1;\n {\n let a = a+2;\
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i64 @foo(i64) {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__struct_test.snap b/crates/mun_codegen/src/snapshots/test__struct_test.snap
index 7c12ba243..c4d871f85 100644
--- a/crates/mun_codegen/src/snapshots/test__struct_test.snap
+++ b/crates/mun_codegen/src/snapshots/test__struct_test.snap
@@ -4,13 +4,54 @@ expression: "struct(value) Bar(float, int, bool, Foo);\nstruct(value) Foo { a: i
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
-%DispatchTable = type { i8* (i8 addrspace(4)*, i8 addrspace(4)*)* }
+%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i8 }
+%struct.MunStructInfo = type { i8 addrspace(4)*, i8 addrspace(4)* addrspace(4)*, %struct.MunTypeInfo addrspace(4)* addrspace(4)*, i16 addrspace(4)*, i16 addrspace(4)*, i16, i16, i8 }
+%DispatchTable = type { i8* addrspace(4)* (i8 addrspace(4)*, i8*)*, i8* addrspace(4)* (i8 addrspace(4)*, i8*)* }
%Baz = type {}
%Bar = type { double, i64, i1, %Foo }
%Foo = type { i64 }
+@"type_info::::name" = private unnamed_addr constant [4 x i8] c"Foo\00"
+@"struct_info::::name" = private unnamed_addr constant [4 x i8] c"Foo\00"
+@"struct_info::::field_names" = private unnamed_addr constant [2 x i8] c"a\00"
+@0 = private unnamed_addr constant [1 x i8 addrspace(4)*] [i8 addrspace(4)* @"struct_info::::field_names"]
+@"type_info::::name" = private unnamed_addr constant [10 x i8] c"core::i64\00"
+@"type_info::" = private unnamed_addr constant { [16 x i8], [10 x i8]*, i8 } { [16 x i8] c"G\13;t\97j8\18\D7M\83`\1D\C8\19%", [10 x i8]* @"type_info::::name", i8 0 }
+@"struct_info::::field_types" = private unnamed_addr constant [1 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::"]
+@1 = private unnamed_addr constant [1 x i16] zeroinitializer
+@2 = private unnamed_addr constant [1 x i16] [i16 8]
+@"type_info::" = private unnamed_addr constant { { [16 x i8], [4 x i8]*, i8 }, %struct.MunStructInfo } { { [16 x i8], [4 x i8]*, i8 } { [16 x i8] c"\13V\C6}z\D1c\8D\81k\FB\82-\D2\C2]", [4 x i8]* @"type_info::::name", i8 1 }, %struct.MunStructInfo { [4 x i8]* @"struct_info::::name", [1 x i8 addrspace(4)*]* @0, [1 x %struct.MunTypeInfo addrspace(4)*]* @"struct_info::::field_types", [1 x i16]* @1, [1 x i16]* @2, i16 1, i16 8, i8 1 } }
+@"type_info::<*const TypeInfo>::name" = private unnamed_addr constant [16 x i8] c"*const TypeInfo\00"
+@"type_info::<*const TypeInfo>" = private unnamed_addr constant { [16 x i8], [16 x i8]*, i8 } { [16 x i8] c"=\A1-\1F\C2\A7\88`d\90\F4\B5\BEE}x", [16 x i8]* @"type_info::<*const TypeInfo>::name", i8 0 }
+@"type_info::::name" = private unnamed_addr constant [10 x i8] c"core::f64\00"
+@"type_info::" = private unnamed_addr constant { [16 x i8], [10 x i8]*, i8 } { [16 x i8] c"`\DBF\9C?YJ%G\AD4\9F\D5\92%A", [10 x i8]* @"type_info::::name", i8 0 }
+@"type_info::::name" = private unnamed_addr constant [11 x i8] c"core::bool\00"
+@"type_info::" = private unnamed_addr constant { [16 x i8], [11 x i8]*, i8 } { [16 x i8] c"x\82\81m t7\03\CB\F8k\81-;\C9\84", [11 x i8]* @"type_info::::name", i8 0 }
+@"type_info::<*const *mut core::void>::name" = private unnamed_addr constant [23 x i8] c"*const *mut core::void\00"
+@"type_info::<*const *mut core::void>" = private unnamed_addr constant { [16 x i8], [23 x i8]*, i8 } { [16 x i8] c"\C5fO\BD\84\DF\06\BFd+\B1\9Abv\CE\00", [23 x i8]* @"type_info::<*const *mut core::void>::name", i8 0 }
+@"type_info::::name" = private unnamed_addr constant [4 x i8] c"Bar\00"
+@"struct_info::::name" = private unnamed_addr constant [4 x i8] c"Bar\00"
+@"struct_info::::field_names" = private unnamed_addr constant [2 x i8] c"0\00"
+@"struct_info::::field_names.1" = private unnamed_addr constant [2 x i8] c"1\00"
+@"struct_info::::field_names.2" = private unnamed_addr constant [2 x i8] c"2\00"
+@"struct_info::::field_names.3" = private unnamed_addr constant [2 x i8] c"3\00"
+@3 = private unnamed_addr constant [4 x i8 addrspace(4)*] [i8 addrspace(4)* @"struct_info::::field_names", i8 addrspace(4)* @"struct_info::::field_names.1", i8 addrspace(4)* @"struct_info::::field_names.2", i8 addrspace(4)* @"struct_info::::field_names.3"]
+@"struct_info::::field_types" = private unnamed_addr constant [4 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::"]
+@4 = private unnamed_addr constant [4 x i16] [i16 0, i16 8, i16 16, i16 24]
+@5 = private unnamed_addr constant [4 x i16] [i16 8, i16 8, i16 1, i16 8]
+@"type_info::" = private unnamed_addr constant { { [16 x i8], [4 x i8]*, i8 }, %struct.MunStructInfo } { { [16 x i8], [4 x i8]*, i8 } { [16 x i8] c"\DD\C3_\88\FAq\B6\EF\14*\E6\1F56FS", [4 x i8]* @"type_info::::name", i8 1 }, %struct.MunStructInfo { [4 x i8]* @"struct_info::::name", [4 x i8 addrspace(4)*]* @3, [4 x %struct.MunTypeInfo addrspace(4)*]* @"struct_info::::field_types", [4 x i16]* @4, [4 x i16]* @5, i16 4, i16 8, i8 1 } }
+@"type_info::<*const core::void>::name" = private unnamed_addr constant [18 x i8] c"*const core::void\00"
+@"type_info::<*const core::void>" = private unnamed_addr constant { [16 x i8], [18 x i8]*, i8 } { [16 x i8] c"\EF\D3\E0ac~\5C\D4\EF\AE\B1}\CA\BE\DA\16", [18 x i8]* @"type_info::<*const core::void>::name", i8 0 }
+@"type_info::<*mut core::void>::name" = private unnamed_addr constant [16 x i8] c"*mut core::void\00"
+@"type_info::<*mut core::void>" = private unnamed_addr constant { [16 x i8], [16 x i8]*, i8 } { [16 x i8] c"\F0Y\22\FC\95\9E\7F\CE\08T\B1\A2\CD\A7\FAz", [16 x i8]* @"type_info::<*mut core::void>::name", i8 0 }
+@"type_info::::name" = private unnamed_addr constant [4 x i8] c"Baz\00"
+@"struct_info::::name" = private unnamed_addr constant [4 x i8] c"Baz\00"
+@"type_info::" = private unnamed_addr constant { { [16 x i8], [4 x i8]*, i8 }, %struct.MunStructInfo } { { [16 x i8], [4 x i8]*, i8 } { [16 x i8] c"\F8\DC\E6\7F,\948\82\82\ED?\A7\97\96\8A|", [4 x i8]* @"type_info::::name", i8 1 }, %struct.MunStructInfo { [4 x i8]* @"struct_info::::name", i8 addrspace(4)* addrspace(4)* null, %struct.MunTypeInfo addrspace(4)* addrspace(4)* null, i16 addrspace(4)* null, i16 addrspace(4)* null, i16 0, i16 1, i8 1 } }
+@global_type_table = private unnamed_addr constant [10 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::<*const TypeInfo>", %struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::<*const *mut core::void>", %struct.MunTypeInfo addrspace(4)* @"type_info::", %struct.MunTypeInfo addrspace(4)* @"type_info::<*const core::void>", %struct.MunTypeInfo addrspace(4)* @"type_info::<*mut core::void>", %struct.MunTypeInfo addrspace(4)* @"type_info::"]
@dispatchTable = global %DispatchTable zeroinitializer
+@allocatorHandle = private unnamed_addr global i8* null
define void @foo() {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__true_is_true.snap b/crates/mun_codegen/src/snapshots/test__true_is_true.snap
index 97257103d..a9923c2d8 100644
--- a/crates/mun_codegen/src/snapshots/test__true_is_true.snap
+++ b/crates/mun_codegen/src/snapshots/test__true_is_true.snap
@@ -4,6 +4,7 @@ expression: "fn test_true():bool {\n true\n}\n\nfn test_false():bool {\n f
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i1 @test_true() {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__update_operators.snap b/crates/mun_codegen/src/snapshots/test__update_operators.snap
index 5d794f463..9db047dfb 100644
--- a/crates/mun_codegen/src/snapshots/test__update_operators.snap
+++ b/crates/mun_codegen/src/snapshots/test__update_operators.snap
@@ -4,6 +4,7 @@ expression: "fn add(a:int, b:int):int {\n let result = a\n result += b\n resu
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i64 @add(i64, i64) {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__update_parameter.snap b/crates/mun_codegen/src/snapshots/test__update_parameter.snap
index 8ac10bef7..755d5891b 100644
--- a/crates/mun_codegen/src/snapshots/test__update_parameter.snap
+++ b/crates/mun_codegen/src/snapshots/test__update_parameter.snap
@@ -4,6 +4,7 @@ expression: "fn add_three(a:int):int {\n a += 3;\n a\n}"
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define i64 @add_three(i64) {
body:
diff --git a/crates/mun_codegen/src/snapshots/test__void_return.snap b/crates/mun_codegen/src/snapshots/test__void_return.snap
index 4b87964e2..4b6620b55 100644
--- a/crates/mun_codegen/src/snapshots/test__void_return.snap
+++ b/crates/mun_codegen/src/snapshots/test__void_return.snap
@@ -4,6 +4,7 @@ expression: "fn bar() {\n let a = 3;\n}\nfn foo(a:int) {\n let c = bar()\n
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
%DispatchTable = type { void ()* }
diff --git a/crates/mun_codegen/src/snapshots/test__while_expr.snap b/crates/mun_codegen/src/snapshots/test__while_expr.snap
index e56439f69..1d0ee2cf3 100644
--- a/crates/mun_codegen/src/snapshots/test__while_expr.snap
+++ b/crates/mun_codegen/src/snapshots/test__while_expr.snap
@@ -1,9 +1,10 @@
---
source: crates/mun_codegen/src/test.rs
-expression: "fn foo(n:int) {\n while n<3 {\n n += 1;\n };\n\n // This will be completely optimized out\n while n<4 {\n break;\n };\n}"
+expression: "fn foo(n:int) {\n while n<3 {\n n += 1;\n };\n\n // This will be completely optimized out\n while n<4 {\n break;\n };\n }"
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
+target triple = "x86-64"
define void @foo(i64) {
body:
diff --git a/crates/mun_codegen/src/symbols.rs b/crates/mun_codegen/src/symbols.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/crates/mun_codegen/src/symbols.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/crates/mun_codegen/src/test.rs b/crates/mun_codegen/src/test.rs
index cba26e441..302629654 100644
--- a/crates/mun_codegen/src/test.rs
+++ b/crates/mun_codegen/src/test.rs
@@ -1,4 +1,4 @@
-use crate::{mock::MockDatabase, IrDatabase};
+use crate::{mock::MockDatabase, IrDatabase, ModuleBuilder};
use hir::{diagnostics::DiagnosticSink, line_index::LineIndex, Module, SourceDatabase};
use inkwell::OptimizationLevel;
use mun_target::spec::Target;
@@ -358,7 +358,7 @@ fn while_expr() {
while n<4 {
break;
};
- }
+ }
"#,
)
}
@@ -512,13 +512,12 @@ fn test_snapshot_with_optimization(text: &str, opt: OptimizationLevel) {
let name = if !messages.is_empty() {
messages.join("\n")
} else {
- format!(
- "{}",
- db.module_ir(file_id)
- .llvm_module
- .print_to_string()
- .to_string()
- )
+ let _module_builder =
+ ModuleBuilder::new(&mut db, file_id).expect("Failed to initialize module builder");
+
+ // Generate IR
+ db.module_ir(file_id);
+ format!("{}", db.module().print_to_string().to_string())
};
insta::assert_snapshot!(insta::_macro_support::AutoName, name, &text);
}
diff --git a/crates/mun_codegen/src/type_info.rs b/crates/mun_codegen/src/type_info.rs
index 65974b5e1..fee303fa6 100644
--- a/crates/mun_codegen/src/type_info.rs
+++ b/crates/mun_codegen/src/type_info.rs
@@ -16,7 +16,7 @@ impl From for u64 {
}
}
-#[derive(Clone, Eq, Debug)]
+#[derive(Clone, Debug, Eq)]
pub struct TypeInfo {
pub guid: Guid,
pub name: String,
@@ -35,6 +35,18 @@ impl PartialEq for TypeInfo {
}
}
+impl Ord for TypeInfo {
+ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+ self.guid.cmp(&other.guid)
+ }
+}
+
+impl PartialOrd for TypeInfo {
+ fn partial_cmp(&self, other: &Self) -> Option {
+ Some(self.cmp(other))
+ }
+}
+
impl TypeInfo {
pub fn new>(name: S, group: TypeGroup) -> TypeInfo {
TypeInfo {
@@ -92,6 +104,12 @@ impl HasStaticTypeInfo for bool {
}
}
+impl HasStaticTypeInfo for std::ffi::c_void {
+ fn type_info() -> TypeInfo {
+ TypeInfo::new("core::void", TypeGroup::FundamentalTypes)
+ }
+}
+
impl HasStaticTypeInfo for *mut T {
fn type_info() -> TypeInfo {
TypeInfo::new(
diff --git a/crates/mun_compiler/src/driver.rs b/crates/mun_compiler/src/driver.rs
index d38f4f5fc..4849391b5 100644
--- a/crates/mun_compiler/src/driver.rs
+++ b/crates/mun_compiler/src/driver.rs
@@ -6,12 +6,9 @@ use crate::{
diagnostics::{diagnostics, Emit},
PathOrInline,
};
-use mun_codegen::IrDatabase;
+use mun_codegen::{IrDatabase, ModuleBuilder};
use mun_hir::{FileId, RelativePathBuf, SourceDatabase, SourceRoot, SourceRootId};
-use std::{
- path::{Path, PathBuf},
- sync::Arc,
-};
+use std::{path::PathBuf, sync::Arc};
mod config;
@@ -123,26 +120,9 @@ impl Driver {
}
impl Driver {
- /// Computes the output path for the assembly of the specified file.
- fn assembly_output_path(&self, file_id: FileId) -> PathBuf {
- let relative_path: RelativePathBuf = self.db.file_relative_path(file_id);
- let original_filename = Path::new(relative_path.file_name().unwrap());
-
- // Add the `munlib` suffix to the original filename
- let output_file_name = original_filename.with_extension("munlib");
-
- // If there is an out dir specified, prepend the output directory
- if let Some(ref out_dir) = self.out_dir {
- out_dir.join(output_file_name)
- } else {
- output_file_name
- }
- }
-
/// Generate an assembly for the given file
- pub fn write_assembly(&self, file_id: FileId) -> Result