Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: Adds data structures #64

Merged
merged 21 commits into from
Jan 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c84a7bf
feat: parsing of data structures
Wodann Nov 23, 2019
9a86797
feat(hir): resolve struct names
Wodann Nov 23, 2019
e241e86
improvement(struct): allow trailing semicolon
Wodann Nov 29, 2019
0b10bb1
feat(tuple): add parsing and HIR lowering for tuples
baszalmstra Nov 30, 2019
0ecdd6b
feat(structs): generate type ir for structs
baszalmstra Nov 30, 2019
7976f07
feat(struct): parsing of record literals
baszalmstra Dec 1, 2019
76e9188
feat(struct): type inference of record literals
Wodann Dec 4, 2019
b2aea8b
feat(struct): type inference of tuple literals
Wodann Dec 4, 2019
a6303a1
feat(struct): add lexing of indices, and parsing and type inferencing…
Wodann Dec 5, 2019
9c9758e
feat(struct): add IR generation for record, tuple, and unit struct li…
Wodann Dec 12, 2019
5d34607
feat(struct): add struct to ABI and runtime dispatch table
Wodann Dec 16, 2019
1069b9e
feat(struct): add IR generation for fields
Wodann Dec 17, 2019
d6dda23
misc(mun_hir): expression validator
baszalmstra Jan 10, 2020
afe18e1
feat: diagnostics for uninitialized variable access
baszalmstra Jan 10, 2020
d53ee2c
feat: struct memory type specifiers
baszalmstra Jan 10, 2020
a288b1f
feat: visibility can now include specifiers
baszalmstra Jan 10, 2020
0d41201
refactor: Renamed Source to InFile and added to diagnostics
baszalmstra Jan 10, 2020
e5f1fe8
misc: better diagnostic for uninitialized access
baszalmstra Jan 10, 2020
0e75842
feat(struct): add validity checks and diagnostics for struct literals
Wodann Jan 11, 2020
26621df
feat: initial very leaky implementation of heap allocation
baszalmstra Jan 11, 2020
a2c7ce7
misc: suggestions from review
baszalmstra Jan 11, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/mun/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test/
8 changes: 0 additions & 8 deletions crates/mun/test/main.mun

This file was deleted.

2 changes: 1 addition & 1 deletion crates/mun_abi/c
Submodule c updated 1 files
+22 −0 include/mun_abi.h
90 changes: 85 additions & 5 deletions crates/mun_abi/src/autogen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,62 @@ fn bindgen_test_layout_FunctionInfo() {
)
);
}
#[doc = " Represents a struct declaration."]
#[doc = ""]
#[doc = " <div rustbindgen derive=\"Clone\" derive=\"Debug\"></div>"]
#[repr(C)]
#[derive(Clone, Debug)]
pub struct StructInfo {
#[doc = " Struct name"]
pub name: *const ::std::os::raw::c_char,
#[doc = " Struct fields' information"]
pub field_types: *const TypeInfo,
#[doc = " Number of fields"]
pub num_fields: u16,
}
#[test]
fn bindgen_test_layout_StructInfo() {
assert_eq!(
::std::mem::size_of::<StructInfo>(),
24usize,
concat!("Size of: ", stringify!(StructInfo))
);
assert_eq!(
::std::mem::align_of::<StructInfo>(),
8usize,
concat!("Alignment of ", stringify!(StructInfo))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<StructInfo>())).name as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(StructInfo),
"::",
stringify!(name)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<StructInfo>())).field_types as *const _ as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(StructInfo),
"::",
stringify!(field_types)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<StructInfo>())).num_fields as *const _ as usize },
16usize,
concat!(
"Offset of field: ",
stringify!(StructInfo),
"::",
stringify!(num_fields)
)
);
}
#[doc = " Represents a module declaration."]
#[doc = ""]
#[doc = " <div rustbindgen derive=\"Debug\"></div>"]
Expand All @@ -218,12 +274,16 @@ pub struct ModuleInfo {
pub functions: *const FunctionInfo,
#[doc = " Number of module functions"]
pub num_functions: u32,
#[doc = " Module structs"]
pub structs: *const StructInfo,
#[doc = " Number of module structs"]
pub num_structs: u32,
}
#[test]
fn bindgen_test_layout_ModuleInfo() {
assert_eq!(
::std::mem::size_of::<ModuleInfo>(),
24usize,
40usize,
concat!("Size of: ", stringify!(ModuleInfo))
);
assert_eq!(
Expand Down Expand Up @@ -261,6 +321,26 @@ fn bindgen_test_layout_ModuleInfo() {
stringify!(num_functions)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<ModuleInfo>())).structs as *const _ as usize },
24usize,
concat!(
"Offset of field: ",
stringify!(ModuleInfo),
"::",
stringify!(structs)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<ModuleInfo>())).num_structs as *const _ as usize },
32usize,
concat!(
"Offset of field: ",
stringify!(ModuleInfo),
"::",
stringify!(num_structs)
)
);
}
#[doc = " Represents a function dispatch table. This is used for runtime linking."]
#[doc = ""]
Expand Down Expand Up @@ -339,7 +419,7 @@ pub struct AssemblyInfo {
fn bindgen_test_layout_AssemblyInfo() {
assert_eq!(
::std::mem::size_of::<AssemblyInfo>(),
64usize,
80usize,
concat!("Size of: ", stringify!(AssemblyInfo))
);
assert_eq!(
Expand All @@ -359,7 +439,7 @@ fn bindgen_test_layout_AssemblyInfo() {
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<AssemblyInfo>())).dispatch_table as *const _ as usize },
24usize,
40usize,
concat!(
"Offset of field: ",
stringify!(AssemblyInfo),
Expand All @@ -369,7 +449,7 @@ fn bindgen_test_layout_AssemblyInfo() {
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<AssemblyInfo>())).dependencies as *const _ as usize },
48usize,
64usize,
concat!(
"Offset of field: ",
stringify!(AssemblyInfo),
Expand All @@ -379,7 +459,7 @@ fn bindgen_test_layout_AssemblyInfo() {
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<AssemblyInfo>())).num_dependencies as *const _ as usize },
56usize,
72usize,
concat!(
"Offset of field: ",
stringify!(AssemblyInfo),
Expand Down
115 changes: 100 additions & 15 deletions crates/mun_abi/src/autogen_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,24 @@ unsafe impl Sync for FunctionSignature {}
unsafe impl Send for FunctionInfo {}
unsafe impl Sync for FunctionInfo {}

impl StructInfo {
/// Returns the struct's name.
pub fn name(&self) -> &str {
unsafe { CStr::from_ptr(self.name) }
.to_str()
.expect("Function name contains invalid UTF8")
}

/// Returns the struct's fields' types.
pub fn field_types(&self) -> &[TypeInfo] {
if self.num_fields == 0 {
&[]
} else {
unsafe { slice::from_raw_parts(self.field_types, self.num_fields as usize) }
}
}
}

impl ModuleInfo {
/// Returns the module's full path.
pub fn path(&self) -> &str {
Expand Down Expand Up @@ -82,6 +100,15 @@ impl ModuleInfo {
unsafe { slice::from_raw_parts(self.functions, self.num_functions as usize) }
}
}

/// Returns the module's structs.
pub fn structs(&self) -> &[StructInfo] {
if self.num_structs == 0 {
&[]
} else {
unsafe { slice::from_raw_parts(self.structs, self.num_structs as usize) }
}
}
}

unsafe impl Send for ModuleInfo {}
Expand Down Expand Up @@ -202,7 +229,7 @@ mod tests {
b: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
};

const FAKE_TYPE_NAME: &'static str = "type-name";
const FAKE_TYPE_NAME: &str = "type-name";

#[test]
fn test_type_info_name() {
Expand Down Expand Up @@ -235,7 +262,7 @@ mod tests {
}
}

const FAKE_FN_NAME: &'static str = "fn-name";
const FAKE_FN_NAME: &str = "fn-name";

#[test]
fn test_fn_signature_name() {
Expand Down Expand Up @@ -296,35 +323,82 @@ mod tests {
assert_eq!(fn_signature.return_type(), return_type);
}

fn fake_module_info(path: &CStr, functions: &[FunctionInfo]) -> ModuleInfo {
fn fake_struct_info(name: &CStr, field_types: &[TypeInfo]) -> StructInfo {
StructInfo {
name: name.as_ptr(),
field_types: field_types.as_ptr(),
num_fields: field_types.len() as u16,
}
}

const FAKE_STRUCT_NAME: &str = "struct-name";

#[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, &[]);

assert_eq!(struct_info.name(), FAKE_STRUCT_NAME);
}

#[test]
fn test_struct_info_field_types_none() {
let field_types = &[];
let struct_name = CString::new(FAKE_STRUCT_NAME).expect("Invalid fake struct name.");
let struct_info = fake_struct_info(&struct_name, field_types);

assert_eq!(struct_info.field_types(), field_types);
}

#[test]
fn test_struct_info_field_types_some() {
let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name.");
let type_info = fake_type_info(&type_name);

let field_types = &[type_info];
let struct_name = CString::new(FAKE_STRUCT_NAME).expect("Invalid fake struct name.");
let struct_info = fake_struct_info(&struct_name, field_types);

assert_eq!(struct_info.field_types(), field_types);
}

fn fake_module_info(
path: &CStr,
functions: &[FunctionInfo],
structs: &[StructInfo],
) -> ModuleInfo {
ModuleInfo {
path: path.as_ptr(),
functions: functions.as_ptr(),
num_functions: functions.len() as u32,
structs: structs.as_ptr(),
num_structs: structs.len() as u32,
}
}

const FAKE_MODULE_PATH: &'static str = "path::to::module";
const FAKE_MODULE_PATH: &str = "path::to::module";

#[test]
fn test_module_info_path() {
let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path.");
let module = fake_module_info(&module_path, &[]);
let module = fake_module_info(&module_path, &[], &[]);

assert_eq!(module.path(), FAKE_MODULE_PATH);
}

#[test]
fn test_module_info_functions_none() {
fn test_module_info_types_none() {
let functions = &[];
let structs = &[];
let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path.");
let module = fake_module_info(&module_path, functions);
let module = fake_module_info(&module_path, functions, structs);

assert_eq!(module.functions().len(), functions.len());
assert_eq!(module.structs().len(), structs.len());
}

#[test]
fn test_module_info_functions_some() {
fn test_module_info_types_some() {
let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name.");
let type_info = fake_type_info(&type_name);

Expand All @@ -336,20 +410,31 @@ mod tests {
signature: fn_signature,
fn_ptr: ptr::null(),
};

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, &[]);
let structs = &[struct_info];

let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path.");
let module = fake_module_info(&module_path, functions);
let module = fake_module_info(&module_path, functions, structs);

let result = module.functions();
assert_eq!(result.len(), functions.len());
for (lhs, rhs) in result.iter().zip(functions.iter()) {
let result_functions = module.functions();
assert_eq!(result_functions.len(), functions.len());
for (lhs, rhs) in result_functions.iter().zip(functions.iter()) {
assert_eq!(lhs.fn_ptr, rhs.fn_ptr);
assert_eq!(lhs.signature.name(), rhs.signature.name());
assert_eq!(lhs.signature.arg_types(), rhs.signature.arg_types());
assert_eq!(lhs.signature.return_type(), rhs.signature.return_type());
assert_eq!(lhs.signature.privacy(), rhs.signature.privacy());
}

let result_structs = module.structs();
assert_eq!(result_structs.len(), structs.len());
for (lhs, rhs) in result_structs.iter().zip(structs.iter()) {
assert_eq!(lhs.name(), rhs.name());
assert_eq!(lhs.field_types(), rhs.field_types());
}
}

fn fake_dispatch_table(
Expand Down Expand Up @@ -555,12 +640,12 @@ mod tests {
}
}

const FAKE_DEPENDENCY: &'static str = "path/to/dependency.dylib";
const FAKE_DEPENDENCY: &str = "path/to/dependency.dylib";

#[test]
fn test_assembly_info_dependencies() {
let module_path = CString::new(FAKE_MODULE_PATH).expect("Invalid fake module path.");
let module = fake_module_info(&module_path, &[]);
let module = fake_module_info(&module_path, &[], &[]);

let dispatch_table = fake_dispatch_table(&[], &mut []);

Expand Down
2 changes: 1 addition & 1 deletion crates/mun_codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
description = "LLVM IR code generation for Mun"

[dependencies]
mun_hir = { path = "../mun_hir" }
hir = { path = "../mun_hir", package = "mun_hir" }
mun_target = { path = "../mun_target" }
mun_lld = { path = "../mun_lld" }
failure = "0.1.5"
Expand Down
3 changes: 2 additions & 1 deletion crates/mun_codegen/src/code_gen.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
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 mun_hir::FileId;
use std::io::{self, Write};
use std::path::Path;

Expand Down Expand Up @@ -61,6 +61,7 @@ pub fn write_module_shared_object(
symbols::gen_reflection_ir(
db,
&module.functions,
&module.structs,
&module.dispatch_table,
&assembly_module,
);
Expand Down
Loading