Skip to content

Commit

Permalink
feat(structs): generate type ir for structs
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra committed Dec 1, 2019
1 parent 74bbd31 commit c5df772
Show file tree
Hide file tree
Showing 21 changed files with 271 additions and 50 deletions.
2 changes: 1 addition & 1 deletion crates/mun_codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ authors = ["The Mun Team <team@mun-lang.org>"]
edition = "2018"

[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
2 changes: 1 addition & 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
6 changes: 3 additions & 3 deletions crates/mun_codegen/src/code_gen/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ use crate::ir::dispatch_table::DispatchTable;
use crate::ir::function;
use crate::values::{BasicValue, GlobalValue};
use crate::IrDatabase;
use hir::{Ty, TypeCtor};
use inkwell::attributes::Attribute;
use inkwell::values::{IntValue, PointerValue, UnnamedAddress};
use inkwell::{
module::{Linkage, Module},
values::{FunctionValue, StructValue},
AddressSpace,
};
use mun_hir::{self as hir, Ty, TypeCtor};
use std::collections::HashMap;
use std::hash::{Hash, Hasher};

Expand Down Expand Up @@ -157,7 +157,7 @@ fn gen_function_info_array<'a, D: IrDatabase>(
db: &D,
types: &AbiTypes,
module: &Module,
functions: impl Iterator<Item = (&'a mun_hir::Function, &'a FunctionValue)>,
functions: impl Iterator<Item = (&'a hir::Function, &'a FunctionValue)>,
) -> GlobalValue {
let function_infos: Vec<StructValue> = functions
.map(|(f, value)| {
Expand Down Expand Up @@ -250,7 +250,7 @@ fn gen_dispatch_table<D: IrDatabase>(
/// for the ABI that `get_info` exposes.
pub(super) fn gen_reflection_ir(
db: &impl IrDatabase,
function_map: &HashMap<mun_hir::Function, FunctionValue>,
function_map: &HashMap<hir::Function, FunctionValue>,
dispatch_table: &DispatchTable,
module: &Module,
) {
Expand Down
2 changes: 1 addition & 1 deletion crates/mun_codegen/src/db.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(clippy::type_repetition_in_bounds)]

use mun_hir as hir;


use crate::{code_gen::symbols::TypeInfo, ir::module::ModuleIR, Context};
use inkwell::{types::AnyTypeEnum, OptimizationLevel};
Expand Down
1 change: 1 addition & 0 deletions crates/mun_codegen/src/ir.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use inkwell::types::{AnyTypeEnum, BasicTypeEnum};

pub mod adt;
pub mod body;
pub(crate) mod dispatch_table;
pub mod function;
Expand Down
24 changes: 24 additions & 0 deletions crates/mun_codegen/src/ir/adt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//use crate::ir::module::Types;
use crate::ir::try_convert_any_to_basic;
use crate::IrDatabase;
use inkwell::types::{AnyTypeEnum, BasicTypeEnum};

pub(super) fn gen_struct_decl(db: &impl IrDatabase, s: hir::Struct) {
if let AnyTypeEnum::StructType(struct_type) = db.type_ir(s.ty(db)) {
if struct_type.is_opaque() {
let field_types: Vec<BasicTypeEnum> = s
.fields(db)
.iter()
.map(|field| {
let field_type = field.ty(db);
try_convert_any_to_basic(db.type_ir(field_type))
.expect("could not convert field type")
})
.collect();

struct_type.set_body(&field_types, false);
}
} else {
unreachable!()
}
}
16 changes: 8 additions & 8 deletions crates/mun_codegen/src/ir/body.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use crate::{ir::dispatch_table::DispatchTable, ir::try_convert_any_to_basic, IrDatabase};
use hir::{
ArithOp, BinaryOp, Body, CmpOp, Expr, ExprId, HirDisplay, InferenceResult, Literal, Ordering,
Pat, PatId, Path, Resolution, Resolver, Statement, TypeCtor,
};
use inkwell::{
builder::Builder,
module::Module,
values::{BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue},
FloatPredicate, IntPredicate,
};
use mun_hir::{
self as hir, ArithOp, BinaryOp, Body, CmpOp, Expr, ExprId, HirDisplay, InferenceResult,
Literal, Ordering, Pat, PatId, Path, Resolution, Resolver, Statement, TypeCtor,
};
use std::{collections::HashMap, mem, sync::Arc};

use inkwell::basic_block::BasicBlock;
Expand All @@ -32,7 +32,7 @@ pub(crate) struct BodyIrGenerator<'a, 'b, D: IrDatabase> {
pat_to_param: HashMap<PatId, inkwell::values::BasicValueEnum>,
pat_to_local: HashMap<PatId, inkwell::values::PointerValue>,
pat_to_name: HashMap<PatId, String>,
function_map: &'a HashMap<mun_hir::Function, FunctionValue>,
function_map: &'a HashMap<hir::Function, FunctionValue>,
dispatch_table: &'b DispatchTable,
active_loop: Option<LoopInfo>,
hir_function: hir::Function,
Expand All @@ -44,7 +44,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
module: &'a Module,
hir_function: hir::Function,
ir_function: FunctionValue,
function_map: &'a HashMap<mun_hir::Function, FunctionValue>,
function_map: &'a HashMap<hir::Function, FunctionValue>,
dispatch_table: &'b DispatchTable,
) -> Self {
// Get the type information from the `hir::Function`
Expand Down Expand Up @@ -136,7 +136,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
tail,
} => self.gen_block(expr, statements, *tail),
Expr::Path(ref p) => {
let resolver = mun_hir::resolver_for_expr(self.body.clone(), self.db, expr);
let resolver = hir::resolver_for_expr(self.body.clone(), self.db, expr);
Some(self.gen_path_expr(p, expr, &resolver))
}
Expr::Literal(lit) => Some(self.gen_literal(lit)),
Expand Down Expand Up @@ -471,7 +471,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
let body = self.body.clone();
match &body[expr] {
Expr::Path(ref p) => {
let resolver = mun_hir::resolver_for_expr(self.body.clone(), self.db, expr);
let resolver = hir::resolver_for_expr(self.body.clone(), self.db, expr);
self.gen_path_place_expr(p, expr, &resolver)
}
_ => unreachable!("invalid place expression"),
Expand Down
6 changes: 3 additions & 3 deletions crates/mun_codegen/src/ir/dispatch_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use crate::IrDatabase;
use inkwell::module::Module;
use inkwell::types::BasicTypeEnum;
use inkwell::values::{BasicValueEnum, PointerValue};
use mun_hir as hir;
use mun_hir::{Body, Expr, ExprId, InferenceResult};

use hir::{Body, Expr, ExprId, InferenceResult};
use std::collections::HashMap;

/// A dispatch table in IR is a struct that contains pointers to all functions that are called from
Expand Down Expand Up @@ -147,7 +147,7 @@ impl<'a, D: IrDatabase> DispatchTableBuilder<'a, D> {
/// 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.
pub fn finalize(self, functions: &HashMap<mun_hir::Function, FunctionValue>) -> DispatchTable {
pub fn finalize(self, functions: &HashMap<hir::Function, FunctionValue>) -> DispatchTable {
// Construct the table body from all the entries in the dispatch table
let table_body: Vec<BasicTypeEnum> = self
.entries
Expand Down
4 changes: 2 additions & 2 deletions crates/mun_codegen/src/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::values::FunctionValue;
use crate::{IrDatabase, Module, OptimizationLevel};
use inkwell::passes::{PassManager, PassManagerBuilder};
use inkwell::types::AnyTypeEnum;
use mun_hir as hir;

use std::collections::HashMap;

/// Constructs a PassManager to optimize functions for the given optimization level.
Expand Down Expand Up @@ -45,7 +45,7 @@ pub(crate) fn gen_body<'a, 'b, D: IrDatabase>(
hir_function: hir::Function,
llvm_function: FunctionValue,
module: &'a Module,
llvm_functions: &'a HashMap<mun_hir::Function, FunctionValue>,
llvm_functions: &'a HashMap<hir::Function, FunctionValue>,
dispatch_table: &'b DispatchTable,
) -> FunctionValue {
let mut code_gen = BodyIrGenerator::new(
Expand Down
14 changes: 11 additions & 3 deletions crates/mun_codegen/src/ir/module.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::ir::dispatch_table::{DispatchTable, DispatchTableBuilder};
use crate::ir::function;
use crate::ir::{adt, function};
use crate::IrDatabase;
use hir::{FileId, ModuleDef};
use inkwell::{module::Module, values::FunctionValue};
use mun_hir::{FileId, ModuleDef};
use std::collections::HashMap;
use std::sync::Arc;

Expand All @@ -15,7 +15,7 @@ pub struct ModuleIR {
pub llvm_module: Module,

/// A mapping from HIR functions to LLVM IR values
pub functions: HashMap<mun_hir::Function, FunctionValue>,
pub functions: HashMap<hir::Function, FunctionValue>,

/// The dispatch table
pub dispatch_table: DispatchTable,
Expand All @@ -27,6 +27,14 @@ pub(crate) fn ir_query(db: &impl IrDatabase, file_id: FileId) -> Arc<ModuleIR> {
.context()
.create_module(db.file_relative_path(file_id).as_str());

// Generate all type definitions
for def in db.module_data(file_id).definitions() {
match def {
ModuleDef::Struct(s) => adt::gen_struct_decl(db, *s),
ModuleDef::BuiltinType(_) | ModuleDef::Function(_) => (),
}
}

// Generate all the function signatures
let mut functions = HashMap::new();
let mut dispatch_table_builder = DispatchTableBuilder::new(db, &llvm_module);
Expand Down
6 changes: 5 additions & 1 deletion crates/mun_codegen/src/ir/ty.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::try_convert_any_to_basic;
use crate::IrDatabase;
use hir::{ApplicationTy, Ty, TypeCtor};
use inkwell::types::{AnyTypeEnum, BasicType, BasicTypeEnum};
use mun_hir::{ApplicationTy, Ty, TypeCtor};

/// Given a mun type, construct an LLVM IR type
pub(crate) fn ir_query(db: &impl IrDatabase, ty: Ty) -> AnyTypeEnum {
Expand Down Expand Up @@ -29,6 +29,10 @@ pub(crate) fn ir_query(db: &impl IrDatabase, ty: Ty) -> AnyTypeEnum {

AnyTypeEnum::FunctionType(fn_type)
}
TypeCtor::Struct(s) => {
let name = s.name(db).to_string();
context.opaque_struct_type(&name).into()
}
_ => unreachable!(),
},
_ => unreachable!("unknown type can not be converted"),
Expand Down
11 changes: 5 additions & 6 deletions crates/mun_codegen/src/mock.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use crate::{IrDatabase, OptimizationLevel};
use mun_hir::{FileId, RelativePathBuf};
use mun_hir::{SourceDatabase, SourceRoot, SourceRootId};
use hir::{FileId, RelativePathBuf, SourceDatabase, SourceRoot, SourceRootId};
use std::sync::Arc;

/// A mock implementation of the IR database. It can be used to set up a simple test case.
#[salsa::database(
mun_hir::SourceDatabaseStorage,
mun_hir::DefDatabaseStorage,
mun_hir::HirDatabaseStorage,
hir::SourceDatabaseStorage,
hir::DefDatabaseStorage,
hir::HirDatabaseStorage,
crate::IrDatabaseStorage
)]
#[derive(Default, Debug)]
Expand Down Expand Up @@ -38,7 +37,7 @@ impl MockDatabase {
source_root.insert_file(rel_path, file_id);

db.set_source_root(source_root_id, Arc::new(source_root));
db.set_optimization_lvl(OptimizationLevel::Default);
db.set_optimization_lvl(OptimizationLevel::None);

let context = crate::Context::create();
db.set_context(Arc::new(context));
Expand Down
19 changes: 19 additions & 0 deletions crates/mun_codegen/src/snapshots/test__struct_test.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
source: crates/mun_codegen/src/test.rs
expression: "struct Bar(float, int, bool, Foo);\nstruct Foo { a: int };\nstruct Baz;\nfn foo() {\n let a: Foo;\n let b: Bar;\n let c: Baz;\n}"
---
; ModuleID = 'main.mun'
source_filename = "main.mun"

%Baz = type {}
%Bar = type { double, i64, i1, %Foo }
%Foo = type { i64 }

define void @foo() {
body:
%c = alloca %Baz
%b = alloca %Bar
%a = alloca %Foo
ret void
}

33 changes: 28 additions & 5 deletions crates/mun_codegen/src/test.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use crate::{mock::MockDatabase, IrDatabase};
use mun_hir::diagnostics::DiagnosticSink;
use mun_hir::line_index::LineIndex;
use mun_hir::Module;
use mun_hir::SourceDatabase;
use hir::{diagnostics::DiagnosticSink, line_index::LineIndex, Module, SourceDatabase};
use inkwell::OptimizationLevel;
use std::cell::RefCell;
use std::sync::Arc;

Expand Down Expand Up @@ -359,15 +357,40 @@ fn while_expr() {
while n<4 {
break;
};
}
"#,
)
}

#[test]
fn struct_test() {
test_snapshot_unoptimized(
r#"
struct Bar(float, int, bool, Foo);
struct Foo { a: int };
struct Baz;
fn foo() {
let a: Foo;
let b: Bar;
let c: Baz;
}
"#,
)
}

fn test_snapshot(text: &str) {
test_snapshot_with_optimization(text, OptimizationLevel::Default);
}

fn test_snapshot_unoptimized(text: &str) {
test_snapshot_with_optimization(text, OptimizationLevel::None);
}

fn test_snapshot_with_optimization(text: &str, opt: OptimizationLevel) {
let text = text.trim().replace("\n ", "\n");

let (db, file_id) = MockDatabase::with_single_file(&text);
let (mut db, file_id) = MockDatabase::with_single_file(&text);
db.set_optimization_lvl(opt);

let line_index: Arc<LineIndex> = db.line_index(file_id);
let messages = RefCell::new(Vec::new());
Expand Down
Loading

0 comments on commit c5df772

Please sign in to comment.