Use Layout over Variable for both build modules

This commit is contained in:
Richard Feldman 2020-03-07 22:29:55 -05:00
parent db4ef45708
commit abe9b8efaa
7 changed files with 259 additions and 206 deletions

View file

@ -13,7 +13,6 @@ use roc_collections::all::ImMap;
use roc_module::symbol::{Interns, Symbol};
use roc_mono::expr::{Expr, Proc, Procs};
use roc_mono::layout::Layout;
use roc_types::subs::{Subs, Variable};
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
/// output in debug builds, but we don't want it to print to stdout in release builds!
@ -23,7 +22,7 @@ const PRINT_FN_VERIFICATION_OUTPUT: bool = true;
#[cfg(not(debug_assertions))]
const PRINT_FN_VERIFICATION_OUTPUT: bool = false;
type Scope<'ctx> = ImMap<Symbol, (Variable, PointerValue<'ctx>)>;
type Scope<'a, 'ctx> = ImMap<Symbol, (Layout<'a>, PointerValue<'ctx>)>;
pub struct Env<'a, 'ctx, 'env> {
pub arena: &'a Bump,
@ -31,13 +30,12 @@ pub struct Env<'a, 'ctx, 'env> {
pub builder: &'env Builder<'ctx>,
pub module: &'ctx Module<'ctx>,
pub interns: Interns,
pub subs: Subs,
pub pointer_bytes: u32,
}
pub fn build_expr<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'ctx>,
scope: &Scope<'a, 'ctx>,
parent: FunctionValue<'ctx>,
expr: &Expr<'a>,
procs: &Procs<'a>,
@ -52,7 +50,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
cond_rhs,
pass,
fail,
ret_var,
ret_layout,
..
} => {
let cond = Branch2 {
@ -60,7 +58,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
cond_rhs,
pass,
fail,
ret_var: *ret_var,
ret_layout: ret_layout.clone(),
};
build_branch2(env, scope, parent, cond, procs)
@ -72,16 +70,12 @@ pub fn build_expr<'a, 'ctx, 'env>(
cond,
branches,
default_branch,
ret_var,
cond_var,
ret_layout,
cond_layout,
} => {
let subs = &env.subs;
let ret_content = subs.get_without_compacting(*ret_var).content;
let ret_layout = Layout::from_content(env.arena, ret_content, subs)
.unwrap_or_else(|_| panic!("TODO generate a runtime error in build_expr here!"));
let ret_type = basic_type_from_layout(env.context, &ret_layout);
let switch_args = SwitchArgs {
cond_var: *cond_var,
cond_layout: cond_layout.clone(),
cond_expr: cond,
branches,
default_branch,
@ -90,16 +84,11 @@ pub fn build_expr<'a, 'ctx, 'env>(
build_switch(env, scope, parent, switch_args, procs)
}
Store(ref stores, ref ret) => {
Store(stores, ret) => {
let mut scope = im_rc::HashMap::clone(scope);
let subs = &env.subs;
let context = &env.context;
for (symbol, var, expr) in stores.iter() {
let content = subs.get_without_compacting(*var).content;
let layout = Layout::from_content(env.arena, content, &subs).unwrap_or_else(|_| {
panic!("TODO generate a runtime error in build_branch2 here!")
});
for (symbol, layout, expr) in stores.iter() {
let val = build_expr(env, &scope, parent, &expr, procs);
let expr_bt = basic_type_from_layout(context, &layout);
let alloca = create_entry_block_alloca(
@ -118,12 +107,12 @@ pub fn build_expr<'a, 'ctx, 'env>(
// access itself!
scope = im_rc::HashMap::clone(&scope);
scope.insert(*symbol, (*var, alloca));
scope.insert(*symbol, (layout.clone(), alloca));
}
build_expr(env, &scope, parent, ret, procs)
}
CallByName(ref symbol, ref args) => match *symbol {
CallByName(symbol, args) => match *symbol {
Symbol::BOOL_OR => {
panic!("TODO create a phi node for ||");
}
@ -134,14 +123,14 @@ pub fn build_expr<'a, 'ctx, 'env>(
let mut arg_vals: Vec<BasicValueEnum> =
Vec::with_capacity_in(args.len(), env.arena);
for arg in args.iter() {
for (arg, _layout) in args.iter() {
arg_vals.push(build_expr(env, scope, parent, arg, procs));
}
call_with_args(*symbol, arg_vals.into_bump_slice(), env)
}
},
FunctionPointer(ref symbol) => {
FunctionPointer(symbol) => {
let ptr = env
.module
.get_function(symbol.ident_string(&env.interns))
@ -151,7 +140,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
BasicValueEnum::PointerValue(ptr)
}
CallByPointer(ref sub_expr, ref args, _var) => {
CallByPointer(sub_expr, args, _var) => {
let mut arg_vals: Vec<BasicValueEnum> = Vec::with_capacity_in(args.len(), env.arena);
for arg in args.iter() {
@ -266,22 +255,18 @@ struct Branch2<'a> {
cond_rhs: &'a Expr<'a>,
pass: &'a Expr<'a>,
fail: &'a Expr<'a>,
ret_var: Variable,
ret_layout: Layout<'a>,
}
fn build_branch2<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'ctx>,
scope: &Scope<'a, 'ctx>,
parent: FunctionValue<'ctx>,
cond: Branch2<'a>,
procs: &Procs<'a>,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
let subs = &env.subs;
let ret_content = subs.get_without_compacting(cond.ret_var).content;
let ret_layout = Layout::from_content(env.arena, ret_content, &subs)
.unwrap_or_else(|_| panic!("TODO generate a runtime error in build_branch2 here!"));
let ret_layout = cond.ret_layout;
let ret_type = basic_type_from_layout(env.context, &ret_layout);
let lhs = build_expr(env, scope, parent, cond.cond_lhs, procs);
@ -313,7 +298,7 @@ fn build_branch2<'a, 'ctx, 'env>(
struct SwitchArgs<'a, 'ctx> {
pub cond_expr: &'a Expr<'a>,
pub cond_var: Variable,
pub cond_layout: Layout<'a>,
pub branches: &'a [(u64, Expr<'a>)],
pub default_branch: &'a Expr<'a>,
pub ret_type: BasicTypeEnum<'ctx>,
@ -321,7 +306,7 @@ struct SwitchArgs<'a, 'ctx> {
fn build_switch<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'ctx>,
scope: &Scope<'a, 'ctx>,
parent: FunctionValue<'ctx>,
switch_args: SwitchArgs<'a, 'ctx>,
procs: &Procs<'a>,
@ -392,7 +377,7 @@ fn build_switch<'a, 'ctx, 'env>(
#[allow(clippy::too_many_arguments)]
fn build_phi2<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'ctx>,
scope: &Scope<'a, 'ctx>,
parent: FunctionValue<'ctx>,
comparison: IntValue<'ctx>,
pass: &'a Expr<'a>,
@ -474,17 +459,12 @@ pub fn build_proc_header<'a, 'ctx, 'env>(
) -> (FunctionValue<'ctx>, Vec<'a, BasicTypeEnum<'ctx>>) {
let args = proc.args;
let arena = env.arena;
let subs = &env.subs;
let context = &env.context;
let ret_content = subs.get_without_compacting(proc.ret_var).content;
// TODO this Layout::from_content is duplicated when building this Proc
let ret_layout = Layout::from_content(env.arena, ret_content, &subs)
.unwrap_or_else(|_| panic!("TODO generate a runtime error in build_proc here!"));
let ret_type = basic_type_from_layout(context, &ret_layout);
let ret_type = basic_type_from_layout(context, &proc.ret_layout);
let mut arg_basic_types = Vec::with_capacity_in(args.len(), arena);
let mut arg_symbols = Vec::new_in(arena);
for (layout, arg_symbol, _var) in args.iter() {
for (layout, arg_symbol) in args.iter() {
let arg_type = basic_type_from_layout(env.context, &layout);
arg_basic_types.push(arg_type);
@ -521,7 +501,7 @@ pub fn build_proc<'a, 'ctx, 'env>(
let mut scope = ImMap::default();
// Add args to scope
for ((arg_val, arg_type), (_, arg_symbol, var)) in
for ((arg_val, arg_type), (layout, arg_symbol)) in
fn_val.get_param_iter().zip(arg_basic_types).zip(args)
{
set_name(arg_val, arg_symbol.ident_string(&env.interns));
@ -531,7 +511,7 @@ pub fn build_proc<'a, 'ctx, 'env>(
builder.build_store(alloca, arg_val);
scope.insert(*arg_symbol, (*var, alloca));
scope.insert(*arg_symbol, (layout.clone(), alloca));
}
let body = build_expr(env, &scope, fn_val, &proc.body, procs);
@ -616,20 +596,7 @@ fn call_with_args<'a, 'ctx, 'env>(
Symbol::LIST_SET => {
debug_assert!(args.len() == 3);
let list_ptr = args[0].into_pointer_value();
let elem_index = args[1].into_int_value();
let elem = args[2];
let builder = env.builder;
let elem_bytes = 8; // TODO Look this up instead of hardcoding it!
let elem_size = env.context.i64_type().const_int(elem_bytes, false);
let offset = builder.build_int_mul(elem_index, elem_size, "MUL_OFFSET");
let elem_ptr = unsafe { builder.build_gep(list_ptr, &[offset], "elem") };
builder.build_store(elem_ptr, elem);
list_ptr.into()
panic!("TODO List.set with clone");
}
Symbol::LIST_SET_IN_PLACE => {
debug_assert!(args.len() == 3);