mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Use specialize_all
This commit is contained in:
parent
639c132ce0
commit
42e3d35564
4 changed files with 81 additions and 47 deletions
|
@ -5,7 +5,6 @@ use inkwell::passes::PassManager;
|
||||||
use inkwell::types::BasicType;
|
use inkwell::types::BasicType;
|
||||||
use inkwell::OptimizationLevel;
|
use inkwell::OptimizationLevel;
|
||||||
use roc_collections::all::ImMap;
|
use roc_collections::all::ImMap;
|
||||||
use roc_collections::all::MutMap;
|
|
||||||
use roc_gen::layout_id::LayoutIds;
|
use roc_gen::layout_id::LayoutIds;
|
||||||
use roc_gen::llvm::build::{
|
use roc_gen::llvm::build::{
|
||||||
build_proc, build_proc_header, get_call_conventions, module_from_builtins, OptLevel,
|
build_proc, build_proc_header, get_call_conventions, module_from_builtins, OptLevel,
|
||||||
|
@ -14,7 +13,7 @@ use roc_gen::llvm::convert::basic_type_from_layout;
|
||||||
use roc_load::file::LoadedModule;
|
use roc_load::file::LoadedModule;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::expr::{Env, Expr, PartialProc, Procs};
|
use roc_mono::expr::{Env, Expr, PartialProc, Procs};
|
||||||
use roc_mono::layout::Layout;
|
use roc_mono::layout::{Layout, LayoutCache};
|
||||||
|
|
||||||
use inkwell::targets::{
|
use inkwell::targets::{
|
||||||
CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetTriple,
|
CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetTriple,
|
||||||
|
@ -23,6 +22,7 @@ use std::path::{Path, PathBuf};
|
||||||
use target_lexicon::{Architecture, OperatingSystem, Triple, Vendor};
|
use target_lexicon::{Architecture, OperatingSystem, Triple, Vendor};
|
||||||
|
|
||||||
// TODO this should probably use more helper functions
|
// TODO this should probably use more helper functions
|
||||||
|
// TODO make this polymorphic in the llvm functions so it can be reused for another backend.
|
||||||
#[allow(clippy::cognitive_complexity)]
|
#[allow(clippy::cognitive_complexity)]
|
||||||
pub fn build(
|
pub fn build(
|
||||||
arena: &Bump,
|
arena: &Bump,
|
||||||
|
@ -225,24 +225,27 @@ pub fn build(
|
||||||
// Populate Procs further and get the low-level Expr from the canonical Expr
|
// Populate Procs further and get the low-level Expr from the canonical Expr
|
||||||
let main_body = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
|
let main_body = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
|
||||||
|
|
||||||
// Put this module's ident_ids back in the interns, so we can use them in env.
|
let mut headers = Vec::with_capacity(procs.pending_specializations.len());
|
||||||
env.interns.all_ident_ids.insert(home, ident_ids);
|
let mut layout_cache = LayoutCache::default();
|
||||||
|
|
||||||
let mut headers = Vec::with_capacity(procs.len());
|
let (mut specializations, runtime_errors) =
|
||||||
let (mut proc_map, runtime_errors) = procs.into_map();
|
roc_mono::expr::specialize_all(&mut mono_env, procs, &mut layout_cache);
|
||||||
|
|
||||||
assert_eq!(runtime_errors, roc_collections::all::MutSet::default());
|
assert_eq!(runtime_errors, roc_collections::all::MutSet::default());
|
||||||
|
|
||||||
|
// Put this module's ident_ids back in the interns, so we can use them in env.
|
||||||
|
// This must happen *after* building the headers, because otherwise there's
|
||||||
|
// a conflicting mutable borrow on ident_ids.
|
||||||
|
env.interns.all_ident_ids.insert(home, ident_ids);
|
||||||
|
|
||||||
// Add all the Proc headers to the module.
|
// Add all the Proc headers to the module.
|
||||||
// We have to do this in a separate pass first,
|
// We have to do this in a separate pass first,
|
||||||
// because their bodies may reference each other.
|
// because their bodies may reference each other.
|
||||||
for (symbol, mut procs_by_layout) in proc_map.drain() {
|
for (symbol, layout, proc) in specializations.drain(..) {
|
||||||
for (layout, proc) in procs_by_layout.drain() {
|
let (fn_val, arg_basic_types) =
|
||||||
let (fn_val, arg_basic_types) =
|
build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc);
|
||||||
build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc);
|
|
||||||
|
|
||||||
headers.push((proc, fn_val, arg_basic_types));
|
headers.push((proc, fn_val, arg_basic_types));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build each proc using its header info.
|
// Build each proc using its header info.
|
||||||
|
|
|
@ -75,23 +75,27 @@ macro_rules! assert_llvm_evals_to {
|
||||||
};
|
};
|
||||||
let main_body = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
|
let main_body = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
|
||||||
|
|
||||||
// Put this module's ident_ids back in the interns, so we can use them in Env.
|
let mut headers = Vec::with_capacity(procs.pending_specializations.len());
|
||||||
env.interns.all_ident_ids.insert(home, ident_ids);
|
let mut layout_cache = roc_mono::layout::LayoutCache::default();
|
||||||
|
|
||||||
let mut headers = Vec::with_capacity(procs.len());
|
let (mut specializations, runtime_errors) =
|
||||||
let (mut proc_map, runtime_errors) = procs.into_map();
|
roc_mono::expr::specialize_all(&mut mono_env, procs, &mut layout_cache);
|
||||||
|
|
||||||
assert_eq!(runtime_errors, roc_collections::all::MutSet::default());
|
assert_eq!(runtime_errors, roc_collections::all::MutSet::default());
|
||||||
|
|
||||||
|
// Put this module's ident_ids back in the interns, so we can use them in env.
|
||||||
|
// This must happen *after* building the headers, because otherwise there's
|
||||||
|
// a conflicting mutable borrow on ident_ids.
|
||||||
|
env.interns.all_ident_ids.insert(home, ident_ids);
|
||||||
|
|
||||||
// Add all the Proc headers to the module.
|
// Add all the Proc headers to the module.
|
||||||
// We have to do this in a separate pass first,
|
// We have to do this in a separate pass first,
|
||||||
// because their bodies may reference each other.
|
// because their bodies may reference each other.
|
||||||
for (symbol, mut procs_by_layout) in proc_map.drain() {
|
for (symbol, layout, proc) in specializations.drain(..) {
|
||||||
for (layout, proc) in procs_by_layout.drain() {
|
let (fn_val, arg_basic_types) =
|
||||||
let (fn_val, arg_basic_types) = build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc);
|
build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc);
|
||||||
|
|
||||||
headers.push((proc, fn_val, arg_basic_types));
|
headers.push((proc, fn_val, arg_basic_types));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build each proc using its header info.
|
// Build each proc using its header info.
|
||||||
|
@ -106,7 +110,9 @@ macro_rules! assert_llvm_evals_to {
|
||||||
fpm.run_on(&fn_val);
|
fpm.run_on(&fn_val);
|
||||||
} else {
|
} else {
|
||||||
// NOTE: If this fails, uncomment the above println to debug.
|
// NOTE: If this fails, uncomment the above println to debug.
|
||||||
panic!("Non-main function failed LLVM verification. Uncomment the above println to debug!");
|
panic!(
|
||||||
|
"Non-main function failed LLVM verification. Uncomment the above println to debug!"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,23 +246,27 @@ macro_rules! assert_opt_evals_to {
|
||||||
};
|
};
|
||||||
let main_body = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
|
let main_body = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
|
||||||
|
|
||||||
// Put this module's ident_ids back in the interns, so we can use them in Env.
|
let mut headers = Vec::with_capacity(procs.pending_specializations.len());
|
||||||
env.interns.all_ident_ids.insert(home, ident_ids);
|
let mut layout_cache = roc_mono::layout::LayoutCache::default();
|
||||||
|
|
||||||
let mut headers = Vec::with_capacity(procs.len());
|
let (mut specializations, runtime_errors) =
|
||||||
let (mut proc_map, runtime_errors) = procs.into_map();
|
roc_mono::expr::specialize_all(&mut mono_env, procs, &mut layout_cache);
|
||||||
|
|
||||||
assert_eq!(runtime_errors, roc_collections::all::MutSet::default());
|
assert_eq!(runtime_errors, roc_collections::all::MutSet::default());
|
||||||
|
|
||||||
|
// Put this module's ident_ids back in the interns, so we can use them in env.
|
||||||
|
// This must happen *after* building the headers, because otherwise there's
|
||||||
|
// a conflicting mutable borrow on ident_ids.
|
||||||
|
env.interns.all_ident_ids.insert(home, ident_ids);
|
||||||
|
|
||||||
// Add all the Proc headers to the module.
|
// Add all the Proc headers to the module.
|
||||||
// We have to do this in a separate pass first,
|
// We have to do this in a separate pass first,
|
||||||
// because their bodies may reference each other.
|
// because their bodies may reference each other.
|
||||||
for (symbol, mut procs_by_layout) in proc_map.drain() {
|
for (symbol, layout, proc) in specializations.drain(..) {
|
||||||
for (layout, proc) in procs_by_layout.drain() {
|
let (fn_val, arg_basic_types) =
|
||||||
let (fn_val, arg_basic_types) = build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc);
|
build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc);
|
||||||
|
|
||||||
headers.push((proc, fn_val, arg_basic_types));
|
headers.push((proc, fn_val, arg_basic_types));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build each proc using its header info.
|
// Build each proc using its header info.
|
||||||
|
@ -271,7 +281,9 @@ macro_rules! assert_opt_evals_to {
|
||||||
fpm.run_on(&fn_val);
|
fpm.run_on(&fn_val);
|
||||||
} else {
|
} else {
|
||||||
// NOTE: If this fails, uncomment the above println to debug.
|
// NOTE: If this fails, uncomment the above println to debug.
|
||||||
panic!("Non-main function failed LLVM verification. Uncomment the above println to debug!");
|
panic!(
|
||||||
|
"Non-main function failed LLVM verification. Uncomment the above println to debug!"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,20 +410,27 @@ macro_rules! emit_expr {
|
||||||
};
|
};
|
||||||
let main_body = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
|
let main_body = Expr::new(&mut mono_env, loc_expr.value, &mut procs);
|
||||||
|
|
||||||
// Put this module's ident_ids back in the interns, so we can use them in Env.
|
let mut headers = Vec::with_capacity(procs.pending_specializations.len());
|
||||||
env.interns.all_ident_ids.insert(home, ident_ids);
|
let mut layout_cache = roc_mono::layout::LayoutCache::default();
|
||||||
|
|
||||||
let mut headers = Vec::with_capacity(procs.len());
|
let (mut specializations, runtime_errors) =
|
||||||
|
roc_mono::expr::specialize_all(&mut mono_env, procs, &mut layout_cache);
|
||||||
|
|
||||||
|
assert_eq!(runtime_errors, roc_collections::all::MutSet::default());
|
||||||
|
|
||||||
|
// Put this module's ident_ids back in the interns, so we can use them in env.
|
||||||
|
// This must happen *after* building the headers, because otherwise there's
|
||||||
|
// a conflicting mutable borrow on ident_ids.
|
||||||
|
env.interns.all_ident_ids.insert(home, ident_ids);
|
||||||
|
|
||||||
// Add all the Proc headers to the module.
|
// Add all the Proc headers to the module.
|
||||||
// We have to do this in a separate pass first,
|
// We have to do this in a separate pass first,
|
||||||
// because their bodies may reference each other.
|
// because their bodies may reference each other.
|
||||||
for (symbol, opt_proc) in procs.as_map().into_iter() {
|
for (symbol, layout, proc) in specializations.drain(..) {
|
||||||
if let Some(proc) = opt_proc {
|
let (fn_val, arg_basic_types) =
|
||||||
let (fn_val, arg_basic_types) = build_proc_header(&env, symbol, &proc);
|
build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc);
|
||||||
|
|
||||||
headers.push((proc, fn_val, arg_basic_types));
|
headers.push((proc, fn_val, arg_basic_types));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build each proc using its header info.
|
// Build each proc using its header info.
|
||||||
|
@ -420,13 +439,15 @@ macro_rules! emit_expr {
|
||||||
// (This approach means we don't have to defensively clone name here.)
|
// (This approach means we don't have to defensively clone name here.)
|
||||||
//
|
//
|
||||||
// println!("\n\nBuilding and then verifying function {}\n\n", name);
|
// println!("\n\nBuilding and then verifying function {}\n\n", name);
|
||||||
build_proc(&env, proc, &procs, fn_val, arg_basic_types);
|
build_proc(&env, &mut layout_ids, proc, fn_val, arg_basic_types);
|
||||||
|
|
||||||
if fn_val.verify(true) {
|
if fn_val.verify(true) {
|
||||||
fpm.run_on(&fn_val);
|
fpm.run_on(&fn_val);
|
||||||
} else {
|
} else {
|
||||||
// NOTE: If this fails, uncomment the above println to debug.
|
// NOTE: If this fails, uncomment the above println to debug.
|
||||||
panic!("Non-main function failed LLVM verification. Uncomment the above println to debug!");
|
panic!(
|
||||||
|
"Non-main function failed LLVM verification. Uncomment the above println to debug!"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ impl Symbol {
|
||||||
.get_name(self.module_id())
|
.get_name(self.module_id())
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
panic!(
|
panic!(
|
||||||
"module_string could not find IdentIds for {:?} in interns {:?}",
|
"module_string could not find IdentIds for module {:?} in {:?}",
|
||||||
self.module_id(),
|
self.module_id(),
|
||||||
interns
|
interns
|
||||||
)
|
)
|
||||||
|
@ -71,7 +71,7 @@ impl Symbol {
|
||||||
.get(&self.module_id())
|
.get(&self.module_id())
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
panic!(
|
panic!(
|
||||||
"ident_string could not find IdentIds for {:?} in interns {:?}",
|
"ident_string could not find IdentIds for module {:?} in {:?}",
|
||||||
self.module_id(),
|
self.module_id(),
|
||||||
interns
|
interns
|
||||||
)
|
)
|
||||||
|
|
|
@ -1432,9 +1432,17 @@ pub fn specialize_all<'a>(
|
||||||
env: &mut Env<'a, '_>,
|
env: &mut Env<'a, '_>,
|
||||||
mut procs: Procs<'a>,
|
mut procs: Procs<'a>,
|
||||||
layout_cache: &mut LayoutCache<'a>,
|
layout_cache: &mut LayoutCache<'a>,
|
||||||
) {
|
) -> (Vec<'a, (Symbol, Layout<'a>, Proc<'a>)>, MutSet<Symbol>) {
|
||||||
|
let mut answer = Vec::with_capacity_in(procs.pending_specializations.len(), env.arena);
|
||||||
|
let mut runtime_errors = MutSet::default();
|
||||||
let mut is_finished = procs.pending_specializations.is_empty();
|
let mut is_finished = procs.pending_specializations.is_empty();
|
||||||
|
|
||||||
|
// TODO replace this synchronous loop with a work-stealing queue which
|
||||||
|
// processes each entry in pending_specializations in parallel, one
|
||||||
|
// module at a time (because the &mut env will need exclusive access to
|
||||||
|
// that module's IdentIds; the only reason Env is &mut in specialize is
|
||||||
|
// that we need to generate unique symbols and register them in them module's
|
||||||
|
// IdentIds).
|
||||||
while !is_finished {
|
while !is_finished {
|
||||||
let Procs {
|
let Procs {
|
||||||
partial_procs,
|
partial_procs,
|
||||||
|
@ -1457,10 +1465,10 @@ pub fn specialize_all<'a>(
|
||||||
|
|
||||||
match specialize(env, &mut procs, name, layout_cache, pending, partial_proc) {
|
match specialize(env, &mut procs, name, layout_cache, pending, partial_proc) {
|
||||||
Ok(proc) => {
|
Ok(proc) => {
|
||||||
// TODO stuff
|
answer.push((name, layout, proc));
|
||||||
}
|
}
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
// TODO runtime error
|
runtime_errors.insert(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1468,6 +1476,8 @@ pub fn specialize_all<'a>(
|
||||||
|
|
||||||
is_finished = procs.pending_specializations.is_empty();
|
is_finished = procs.pending_specializations.is_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(answer, runtime_errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn specialize<'a>(
|
fn specialize<'a>(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue