Use intern tables over .emit()

This commit is contained in:
Richard Feldman 2020-02-24 23:50:02 -05:00
parent 3f35aa1f61
commit 1899f30912
5 changed files with 59 additions and 47 deletions

View File

@ -15,7 +15,7 @@ use cranelift_module::{Backend, FuncId, Linkage, Module};
use crate::collections::ImMap;
use crate::crane::convert::{sig_from_layout, type_from_layout};
use crate::module::symbol::Symbol;
use crate::module::symbol::{Interns, Symbol};
use crate::mono::expr::{Expr, Proc, Procs};
use crate::mono::layout::{Builtin, Layout};
use crate::subs::{Subs, Variable};
@ -34,6 +34,7 @@ pub struct Env<'a> {
pub arena: &'a Bump,
pub cfg: TargetFrontendConfig,
pub subs: Subs,
pub interns: Interns,
}
pub fn build_expr<'a, B: Backend>(
@ -421,7 +422,7 @@ fn build_switch<'a, B: Backend>(
pub fn declare_proc<'a, B: Backend>(
env: &Env<'a>,
module: &mut Module<B>,
name: Symbol,
symbol: Symbol,
proc: &Proc<'a>,
) -> (FuncId, Signature) {
let args = proc.args;
@ -448,8 +449,8 @@ pub fn declare_proc<'a, B: Backend>(
// Declare the function in the module
let fn_id = module
.declare_function(&name.emit(), Linkage::Local, &sig)
.unwrap_or_else(|err| panic!("Error when building function {:?} - {:?}", name, err));
.declare_function(symbol.ident_string(&env.interns), Linkage::Local, &sig)
.unwrap_or_else(|err| panic!("Error when building function {:?} - {:?}", symbol, err));
(fn_id, sig)
}

View File

@ -10,7 +10,7 @@ use inkwell::{FloatPredicate, IntPredicate};
use crate::collections::ImMap;
use crate::llvm::convert::{basic_type_from_layout, get_fn_type};
use crate::module::symbol::Symbol;
use crate::module::symbol::{Interns, Symbol};
use crate::mono::expr::{Expr, Proc, Procs};
use crate::mono::layout::Layout;
use crate::subs::{Subs, Variable};
@ -30,6 +30,7 @@ pub struct Env<'a, 'ctx, 'env> {
pub context: &'ctx Context,
pub builder: &'env Builder<'ctx>,
pub module: &'ctx Module<'ctx>,
pub interns: Interns,
pub subs: Subs,
}
@ -100,7 +101,12 @@ pub fn build_expr<'a, 'ctx, 'env>(
});
let val = build_expr(env, &scope, parent, &expr, procs);
let expr_bt = basic_type_from_layout(context, &layout);
let alloca = create_entry_block_alloca(env, parent, expr_bt, &symbol.emit());
let alloca = create_entry_block_alloca(
env,
parent,
expr_bt,
symbol.ident_string(&env.interns),
);
env.builder.build_store(alloca, val);
@ -133,7 +139,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
let fn_val = env
.module
.get_function(&symbol.emit())
.get_function(symbol.ident_string(&env.interns))
.unwrap_or_else(|| panic!("Unrecognized function: {:?}", symbol));
let call = env.builder.build_call(fn_val, arg_vals.as_slice(), "tmp");
@ -146,7 +152,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
FunctionPointer(ref symbol) => {
let ptr = env
.module
.get_function(&symbol.emit())
.get_function(symbol.ident_string(&env.interns))
.unwrap_or_else(|| panic!("Could not get pointer to unknown function {:?}", symbol))
.as_global_value()
.as_pointer_value();
@ -177,9 +183,11 @@ pub fn build_expr<'a, 'ctx, 'env>(
.unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer."))
}
Load(name) => match scope.get(name) {
Some((_, ptr)) => env.builder.build_load(*ptr, &name.emit()),
None => panic!("Could not find a var for {:?} in scope {:?}", name, scope),
Load(symbol) => match scope.get(symbol) {
Some((_, ptr)) => env
.builder
.build_load(*ptr, symbol.ident_string(&env.interns)),
None => panic!("Could not find a var for {:?} in scope {:?}", symbol, scope),
},
_ => {
panic!("I don't yet know how to LLVM build {:?}", expr);
@ -395,7 +403,7 @@ pub fn create_entry_block_alloca<'a, 'ctx>(
pub fn build_proc<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
name: Symbol,
symbol: Symbol,
proc: Proc<'a>,
procs: &Procs<'a>,
) -> FunctionValue<'ctx> {
@ -409,20 +417,22 @@ pub fn build_proc<'a, 'ctx, 'env>(
.unwrap_or_else(|_| panic!("TODO generate a runtime error in build_proc here!"));
let ret_type = basic_type_from_layout(context, &ret_layout);
let mut arg_basic_types = Vec::with_capacity_in(args.len(), arena);
let mut arg_names = Vec::new_in(arena);
let mut arg_symbols = Vec::new_in(arena);
for (layout, name, _var) in args.iter() {
for (layout, arg_symbol, _var) in args.iter() {
let arg_type = basic_type_from_layout(env.context, &layout);
arg_basic_types.push(arg_type);
arg_names.push(name);
arg_symbols.push(arg_symbol);
}
let fn_type = get_fn_type(&ret_type, &arg_basic_types);
let fn_val = env
.module
.add_function(&name.emit(), fn_type, Some(Linkage::Private));
let fn_val = env.module.add_function(
symbol.ident_string(&env.interns),
fn_type,
Some(Linkage::Private),
);
// Add a basic block for the entry point
let entry = context.append_basic_block(fn_val, "entry");
@ -433,16 +443,17 @@ pub fn build_proc<'a, 'ctx, 'env>(
let mut scope = ImMap::default();
// Add args to scope
for ((arg_val, arg_type), (_, arg_name, var)) in
for ((arg_val, arg_type), (_, arg_symbol, var)) in
fn_val.get_param_iter().zip(arg_basic_types).zip(args)
{
set_name(arg_val, &arg_name.emit());
set_name(arg_val, arg_symbol.ident_string(&env.interns));
let alloca = create_entry_block_alloca(env, fn_val, arg_type, &arg_name.emit());
let alloca =
create_entry_block_alloca(env, fn_val, arg_type, arg_symbol.ident_string(&env.interns));
builder.build_store(alloca, arg_val);
scope.insert(arg_name.clone(), (*var, alloca));
scope.insert(*arg_symbol, (*var, alloca));
}
let body = build_expr(env, &scope, fn_val, &proc.body, procs);

View File

@ -89,13 +89,6 @@ impl Symbol {
.into()
}
}
/// TODO This function should be deleted, and replaced by using intern table
/// lookups instead. (Everywhere this function is used, an &str is expected anyway,
/// so using this leads to a ton of unnecessary allocations.)
pub fn emit(self) -> String {
format!("${}", self.0)
}
}
/// Rather than displaying as this:

View File

@ -21,11 +21,11 @@ pub struct Proc<'a> {
pub ret_var: Variable,
}
struct Env<'a> {
struct Env<'a, 'i> {
pub arena: &'a Bump,
pub subs: &'a Subs,
pub home: ModuleId,
pub ident_ids: IdentIds,
pub ident_ids: &'i mut IdentIds,
}
#[derive(Clone, Debug, PartialEq)]
@ -115,7 +115,7 @@ impl<'a> Expr<'a> {
can_expr: can::expr::Expr,
procs: &mut Procs<'a>,
home: ModuleId,
ident_ids: IdentIds,
ident_ids: &mut IdentIds,
) -> Self {
let mut env = Env {
arena,
@ -129,7 +129,7 @@ impl<'a> Expr<'a> {
}
fn from_can<'a>(
env: &mut Env<'a>,
env: &mut Env<'a, '_>,
can_expr: can::expr::Expr,
procs: &mut Procs<'a>,
name: Option<Symbol>,
@ -292,7 +292,7 @@ fn from_can<'a>(
}
fn add_closure<'a>(
env: &mut Env<'a>,
env: &mut Env<'a, '_>,
name: Symbol,
can_body: can::expr::Expr,
ret_var: Variable,
@ -339,7 +339,7 @@ fn add_closure<'a>(
}
fn store_pattern<'a>(
env: &mut Env<'a>,
env: &mut Env<'a, '_>,
can_pat: Pattern,
can_expr: can::expr::Expr,
var: Variable,
@ -384,7 +384,7 @@ fn gen_closure_name(procs: &Procs<'_>, ident_ids: &mut IdentIds, home: ModuleId)
}
fn from_can_when<'a>(
env: &mut Env<'a>,
env: &mut Env<'a, '_>,
cond_var: Variable,
expr_var: Variable,
loc_cond: Located<can::expr::Expr>,

View File

@ -45,7 +45,7 @@ mod test_gen {
let mut ctx = module.make_context();
let mut func_ctx = FunctionBuilderContext::new();
let CanExprOut { loc_expr, var_store, var, constraint, home, mut interns, .. } = can_expr($src);
let CanExprOut { loc_expr, var_store, var, constraint, home, interns, .. } = can_expr($src);
let subs = Subs::new(var_store.into());
let mut unify_problems = Vec::new();
let (content, solved) = infer_expr(subs, &mut unify_problems, &constraint, var);
@ -75,16 +75,20 @@ mod test_gen {
// Compile and add all the Procs before adding main
let mut procs = MutMap::default();
let env = roc::crane::build::Env {
let mut env = roc::crane::build::Env {
arena: &arena,
subs,
interns,
cfg,
};
let ident_ids = interns.all_ident_ids.remove(&home).unwrap();
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr
let mono_expr = Expr::new(&arena, &env.subs, loc_expr.value, &mut procs, home, ident_ids);
let mono_expr = Expr::new(&arena, &env.subs, loc_expr.value, &mut procs, home, &mut ident_ids);
// Put this module's ident_ids back in the interns
env.interns.all_ident_ids.insert(home, ident_ids);
let mut scope = ImMap::default();
let mut declared = Vec::with_capacity(procs.len());
@ -174,7 +178,7 @@ mod test_gen {
macro_rules! assert_llvm_evals_to {
($src:expr, $expected:expr, $ty:ty) => {
let arena = Bump::new();
let CanExprOut { loc_expr, var_store, var, constraint, home, mut interns, .. } = can_expr($src);
let CanExprOut { loc_expr, var_store, var, constraint, home, interns, .. } = can_expr($src);
let subs = Subs::new(var_store.into());
let mut unify_problems = Vec::new();
let (content, solved) = infer_expr(subs, &mut unify_problems, &constraint, var);
@ -209,19 +213,22 @@ mod test_gen {
let main_fn_name = "$Test.main";
// Compile and add all the Procs before adding main
let mut procs = MutMap::default();
let env = roc::llvm::build::Env {
let mut env = roc::llvm::build::Env {
arena: &arena,
subs,
builder: &builder,
context: &context,
interns,
module: arena.alloc(module),
};
let ident_ids = interns.all_ident_ids.remove(&home).unwrap();
let mut procs = MutMap::default();
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
// Populate Procs and get the low-level Expr from the canonical Expr
let main_body = Expr::new(&arena, &env.subs, loc_expr.value, &mut procs, home, ident_ids);
let main_body = Expr::new(&arena, &env.subs, loc_expr.value, &mut procs, home, &mut ident_ids);
// Put this module's ident_ids back in the interns, so we can use them in Env.
env.interns.all_ident_ids.insert(home, ident_ids);
// Add all the Procs to the module
for (name, opt_proc) in procs.clone() {