Merge pull request #670 from rtfeldman/mutual-recursion-codegen

enable the one mutual-recursive function we have
This commit is contained in:
Richard Feldman 2020-11-09 23:16:19 -05:00 committed by GitHub
commit 3f12ba27c5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 93 additions and 107 deletions

View file

@ -47,7 +47,8 @@ pub fn build_file(
let app_o_file = roc_file_path.with_file_name("roc_app.o"); let app_o_file = roc_file_path.with_file_name("roc_app.o");
let buf = &mut String::with_capacity(1024); let buf = &mut String::with_capacity(1024);
for (module_id, module_timing) in loaded.timings.iter() { let mut it = loaded.timings.iter().peekable();
while let Some((module_id, module_timing)) = it.next() {
let module_name = loaded.interns.module_name(*module_id); let module_name = loaded.interns.module_name(*module_id);
buf.push_str(" "); buf.push_str(" ");
@ -60,9 +61,23 @@ pub fn build_file(
report_timing(buf, "Canonicalize", module_timing.canonicalize); report_timing(buf, "Canonicalize", module_timing.canonicalize);
report_timing(buf, "Constrain", module_timing.constrain); report_timing(buf, "Constrain", module_timing.constrain);
report_timing(buf, "Solve", module_timing.solve); report_timing(buf, "Solve", module_timing.solve);
report_timing(
buf,
"Find Specializations",
module_timing.find_specializations,
);
report_timing(
buf,
"Make Specializations",
module_timing.make_specializations,
);
report_timing(buf, "Other", module_timing.other()); report_timing(buf, "Other", module_timing.other());
buf.push('\n'); buf.push('\n');
report_timing(buf, "Total", module_timing.total()); report_timing(buf, "Total", module_timing.total());
if it.peek().is_some() {
buf.push('\n');
}
} }
println!( println!(

View file

@ -251,8 +251,8 @@ fn num_binop(symbol: Symbol, var_store: &mut VarStore, op: LowLevel) -> Def {
) )
} }
/// Num a, Num a -> Bool /// Num a, Num a -> b
fn num_bool_binop(symbol: Symbol, var_store: &mut VarStore, op: LowLevel) -> Def { fn num_num_other_binop(symbol: Symbol, var_store: &mut VarStore, op: LowLevel) -> Def {
let num_var = var_store.fresh(); let num_var = var_store.fresh();
let bool_var = var_store.fresh(); let bool_var = var_store.fresh();
let body = RunLowLevel { let body = RunLowLevel {
@ -381,27 +381,27 @@ fn num_mul(symbol: Symbol, var_store: &mut VarStore) -> Def {
/// Num.isGt : Num a, Num a -> Bool /// Num.isGt : Num a, Num a -> Bool
fn num_gt(symbol: Symbol, var_store: &mut VarStore) -> Def { fn num_gt(symbol: Symbol, var_store: &mut VarStore) -> Def {
num_bool_binop(symbol, var_store, LowLevel::NumGt) num_num_other_binop(symbol, var_store, LowLevel::NumGt)
} }
/// Num.isGte : Num a, Num a -> Bool /// Num.isGte : Num a, Num a -> Bool
fn num_gte(symbol: Symbol, var_store: &mut VarStore) -> Def { fn num_gte(symbol: Symbol, var_store: &mut VarStore) -> Def {
num_bool_binop(symbol, var_store, LowLevel::NumGte) num_num_other_binop(symbol, var_store, LowLevel::NumGte)
} }
/// Num.isLt : Num a, Num a -> Bool /// Num.isLt : Num a, Num a -> Bool
fn num_lt(symbol: Symbol, var_store: &mut VarStore) -> Def { fn num_lt(symbol: Symbol, var_store: &mut VarStore) -> Def {
num_bool_binop(symbol, var_store, LowLevel::NumLt) num_num_other_binop(symbol, var_store, LowLevel::NumLt)
} }
/// Num.isLte : Num a, Num a -> Num a /// Num.isLte : Num a, Num a -> Bool
fn num_lte(symbol: Symbol, var_store: &mut VarStore) -> Def { fn num_lte(symbol: Symbol, var_store: &mut VarStore) -> Def {
num_bool_binop(symbol, var_store, LowLevel::NumLte) num_num_other_binop(symbol, var_store, LowLevel::NumLte)
} }
/// Num.compare : Num a, Num a -> [ LT, EQ, GT ] /// Num.compare : Num a, Num a -> [ LT, EQ, GT ]
fn num_compare(symbol: Symbol, var_store: &mut VarStore) -> Def { fn num_compare(symbol: Symbol, var_store: &mut VarStore) -> Def {
num_bool_binop(symbol, var_store, LowLevel::NumCompare) num_num_other_binop(symbol, var_store, LowLevel::NumCompare)
} }
/// Num.sin : Float -> Float /// Num.sin : Float -> Float

View file

@ -304,6 +304,13 @@ fn fix_values_captured_in_closure_defs(
defs: &mut Vec<crate::def::Def>, defs: &mut Vec<crate::def::Def>,
no_capture_symbols: &mut MutSet<Symbol>, no_capture_symbols: &mut MutSet<Symbol>,
) { ) {
// recursive defs cannot capture each other
for def in defs.iter() {
no_capture_symbols.extend(crate::pattern::symbols_from_pattern(&def.loc_pattern.value));
}
// TODO mutually recursive functions should both capture the union of both their capture sets
for def in defs.iter_mut() { for def in defs.iter_mut() {
fix_values_captured_in_closure_def(def, no_capture_symbols); fix_values_captured_in_closure_def(def, no_capture_symbols);
} }

View file

@ -13,15 +13,7 @@ mod helpers;
#[cfg(test)] #[cfg(test)]
mod gen_num { mod gen_num {
/* use roc_std::RocOrder;
use inkwell::passes::PassManager;
use inkwell::types::BasicType;
use inkwell::OptimizationLevel;
use roc_gen::llvm::build::{build_proc, build_proc_header};
use roc_gen::llvm::convert::basic_type_from_layout;
use roc_mono::layout::Layout;
use roc_types::subs::Subs;
*/
#[test] #[test]
fn f64_sqrt() { fn f64_sqrt() {
@ -584,86 +576,16 @@ mod gen_num {
#[test] #[test]
fn int_compare() { fn int_compare() {
assert_evals_to!( assert_evals_to!("Num.compare 0 1", RocOrder::Lt, RocOrder);
indoc!( assert_evals_to!("Num.compare 1 1", RocOrder::Eq, RocOrder);
r#" assert_evals_to!("Num.compare 1 0", RocOrder::Gt, RocOrder);
when Num.compare 0 1 is
LT -> 0
EQ -> 1
GT -> 2
"#
),
0,
i64
);
assert_evals_to!(
indoc!(
r#"
when Num.compare 1 1 is
LT -> 0
EQ -> 1
GT -> 2
"#
),
1,
i64
);
assert_evals_to!(
indoc!(
r#"
when Num.compare 1 0 is
LT -> 0
EQ -> 1
GT -> 2
"#
),
2,
i64
);
} }
#[test] #[test]
fn float_compare() { fn float_compare() {
assert_evals_to!( assert_evals_to!("Num.compare 0.01 3.14", RocOrder::Lt, RocOrder);
indoc!( assert_evals_to!("Num.compare 3.14 3.14", RocOrder::Eq, RocOrder);
r#" assert_evals_to!("Num.compare 3.14 0.01", RocOrder::Gt, RocOrder);
when Num.compare 0 3.14 is
LT -> 0
EQ -> 1
GT -> 2
"#
),
0,
i64
);
assert_evals_to!(
indoc!(
r#"
when Num.compare 3.14 3.14 is
LT -> 0
EQ -> 1
GT -> 2
"#
),
1,
i64
);
assert_evals_to!(
indoc!(
r#"
when Num.compare 3.14 0 is
LT -> 0
EQ -> 1
GT -> 2
"#
),
2,
i64
);
} }
#[test] #[test]

View file

@ -88,7 +88,7 @@ mod gen_tags {
} }
#[test] #[test]
fn applied_tag_just_unit() { fn applied_tag_just_enum() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
@ -105,7 +105,7 @@ mod gen_tags {
"# "#
), ),
(0, 2), (0, 2),
(i64, i64) (i64, u8)
); );
} }
@ -236,7 +236,6 @@ mod gen_tags {
// } // }
#[test] #[test]
#[ignore]
fn even_odd() { fn even_odd() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(

View file

@ -419,6 +419,7 @@ fn start_phase<'a>(module_id: ModuleId, phase: Phase, state: &mut State<'a>) ->
subs, subs,
procs, procs,
layout_cache, layout_cache,
module_timing,
} = found_specializations; } = found_specializations;
BuildTask::MakeSpecializations { BuildTask::MakeSpecializations {
@ -428,6 +429,7 @@ fn start_phase<'a>(module_id: ModuleId, phase: Phase, state: &mut State<'a>) ->
procs, procs,
layout_cache, layout_cache,
specializations_we_must_make, specializations_we_must_make,
module_timing,
} }
} }
} }
@ -494,6 +496,7 @@ pub struct FoundSpecializationsModule<'a> {
pub layout_cache: LayoutCache<'a>, pub layout_cache: LayoutCache<'a>,
pub procs: Procs<'a>, pub procs: Procs<'a>,
pub subs: Subs, pub subs: Subs,
pub module_timing: ModuleTiming,
} }
#[derive(Debug)] #[derive(Debug)]
@ -565,6 +568,7 @@ enum Msg<'a> {
procs: Procs<'a>, procs: Procs<'a>,
problems: Vec<roc_mono::ir::MonoProblem>, problems: Vec<roc_mono::ir::MonoProblem>,
solved_subs: Solved<Subs>, solved_subs: Solved<Subs>,
module_timing: ModuleTiming,
}, },
MadeSpecializations { MadeSpecializations {
module_id: ModuleId, module_id: ModuleId,
@ -573,6 +577,7 @@ enum Msg<'a> {
external_specializations_requested: MutMap<ModuleId, ExternalSpecializations>, external_specializations_requested: MutMap<ModuleId, ExternalSpecializations>,
procedures: MutMap<(Symbol, Layout<'a>), Proc<'a>>, procedures: MutMap<(Symbol, Layout<'a>), Proc<'a>>,
problems: Vec<roc_mono::ir::MonoProblem>, problems: Vec<roc_mono::ir::MonoProblem>,
module_timing: ModuleTiming,
subs: Subs, subs: Subs,
}, },
@ -660,6 +665,8 @@ pub struct ModuleTiming {
pub canonicalize: Duration, pub canonicalize: Duration,
pub constrain: Duration, pub constrain: Duration,
pub solve: Duration, pub solve: Duration,
pub find_specializations: Duration,
pub make_specializations: Duration,
// TODO pub monomorphize: Duration, // TODO pub monomorphize: Duration,
/// Total duration will always be more than the sum of the other fields, due /// Total duration will always be more than the sum of the other fields, due
/// to things like state lookups in between phases, waiting on other threads, etc. /// to things like state lookups in between phases, waiting on other threads, etc.
@ -676,6 +683,8 @@ impl ModuleTiming {
canonicalize: Duration::default(), canonicalize: Duration::default(),
constrain: Duration::default(), constrain: Duration::default(),
solve: Duration::default(), solve: Duration::default(),
find_specializations: Duration::default(),
make_specializations: Duration::default(),
start_time, start_time,
end_time: start_time, // just for now; we'll overwrite this at the end end_time: start_time, // just for now; we'll overwrite this at the end
} }
@ -694,6 +703,8 @@ impl ModuleTiming {
canonicalize, canonicalize,
constrain, constrain,
solve, solve,
find_specializations,
make_specializations,
start_time, start_time,
end_time, end_time,
} = self; } = self;
@ -702,6 +713,8 @@ impl ModuleTiming {
.duration_since(*start_time) .duration_since(*start_time)
.ok() .ok()
.and_then(|t| { .and_then(|t| {
t.checked_sub(*make_specializations).and_then(|t| {
t.checked_sub(*find_specializations).and_then(|t| {
t.checked_sub(*solve).and_then(|t| { t.checked_sub(*solve).and_then(|t| {
t.checked_sub(*constrain).and_then(|t| { t.checked_sub(*constrain).and_then(|t| {
t.checked_sub(*canonicalize).and_then(|t| { t.checked_sub(*canonicalize).and_then(|t| {
@ -713,6 +726,8 @@ impl ModuleTiming {
}) })
}) })
}) })
})
})
.unwrap_or_else(Duration::default) .unwrap_or_else(Duration::default)
} }
} }
@ -767,6 +782,7 @@ enum BuildTask<'a> {
procs: Procs<'a>, procs: Procs<'a>,
layout_cache: LayoutCache<'a>, layout_cache: LayoutCache<'a>,
specializations_we_must_make: ExternalSpecializations, specializations_we_must_make: ExternalSpecializations,
module_timing: ModuleTiming,
}, },
} }
@ -1531,6 +1547,7 @@ fn update<'a>(
ident_ids, ident_ids,
layout_cache, layout_cache,
problems: _, problems: _,
module_timing,
} => { } => {
log!("found specializations for {:?}", module_id); log!("found specializations for {:?}", module_id);
let subs = solved_subs.into_inner(); let subs = solved_subs.into_inner();
@ -1554,6 +1571,7 @@ fn update<'a>(
procs, procs,
ident_ids, ident_ids,
subs, subs,
module_timing,
}; };
state state
@ -1579,6 +1597,7 @@ fn update<'a>(
procedures, procedures,
external_specializations_requested, external_specializations_requested,
problems, problems,
module_timing,
.. ..
} => { } => {
log!("made specializations for {:?}", module_id); log!("made specializations for {:?}", module_id);
@ -1606,12 +1625,12 @@ fn update<'a>(
state.constrained_ident_ids.insert(module_id, ident_ids); state.constrained_ident_ids.insert(module_id, ident_ids);
state.timings.insert(module_id, module_timing);
if work.is_empty() if work.is_empty()
&& state.dependencies.solved_all() && state.dependencies.solved_all()
&& state.goal_phase == Phase::MakeSpecializations && state.goal_phase == Phase::MakeSpecializations
{ {
// state.timings.insert(module_id, module_timing);
// display the mono IR of the module, for debug purposes // display the mono IR of the module, for debug purposes
if roc_mono::ir::PRETTY_PRINT_IR_SYMBOLS { if roc_mono::ir::PRETTY_PRINT_IR_SYMBOLS {
let procs_string = state let procs_string = state
@ -3052,7 +3071,9 @@ fn make_specializations<'a>(
mut procs: Procs<'a>, mut procs: Procs<'a>,
mut layout_cache: LayoutCache<'a>, mut layout_cache: LayoutCache<'a>,
specializations_we_must_make: ExternalSpecializations, specializations_we_must_make: ExternalSpecializations,
mut module_timing: ModuleTiming,
) -> Msg<'a> { ) -> Msg<'a> {
let make_specializations_start = SystemTime::now();
let mut mono_problems = Vec::new(); let mut mono_problems = Vec::new();
// do the thing // do the thing
let mut mono_env = roc_mono::ir::Env { let mut mono_env = roc_mono::ir::Env {
@ -3080,6 +3101,11 @@ fn make_specializations<'a>(
let external_specializations_requested = procs.externals_we_need.clone(); let external_specializations_requested = procs.externals_we_need.clone();
let procedures = procs.get_specialized_procs_without_rc(mono_env.arena); let procedures = procs.get_specialized_procs_without_rc(mono_env.arena);
let make_specializations_end = SystemTime::now();
module_timing.make_specializations = make_specializations_end
.duration_since(make_specializations_start)
.unwrap();
Msg::MadeSpecializations { Msg::MadeSpecializations {
module_id: home, module_id: home,
ident_ids, ident_ids,
@ -3088,6 +3114,7 @@ fn make_specializations<'a>(
problems: mono_problems, problems: mono_problems,
subs, subs,
external_specializations_requested, external_specializations_requested,
module_timing,
} }
} }
@ -3098,12 +3125,12 @@ fn build_pending_specializations<'a>(
home: ModuleId, home: ModuleId,
mut ident_ids: IdentIds, mut ident_ids: IdentIds,
decls: Vec<Declaration>, decls: Vec<Declaration>,
// TODO use this? mut module_timing: ModuleTiming,
_module_timing: ModuleTiming,
mut layout_cache: LayoutCache<'a>, mut layout_cache: LayoutCache<'a>,
// TODO remove // TODO remove
exposed_to_host: MutMap<Symbol, Variable>, exposed_to_host: MutMap<Symbol, Variable>,
) -> Msg<'a> { ) -> Msg<'a> {
let find_specializations_start = SystemTime::now();
let mut procs = Procs::default(); let mut procs = Procs::default();
let mut mono_problems = std::vec::Vec::new(); let mut mono_problems = std::vec::Vec::new();
@ -3149,6 +3176,11 @@ fn build_pending_specializations<'a>(
let problems = mono_env.problems.to_vec(); let problems = mono_env.problems.to_vec();
let find_specializations_end = SystemTime::now();
module_timing.find_specializations = find_specializations_end
.duration_since(find_specializations_start)
.unwrap();
Msg::FoundSpecializations { Msg::FoundSpecializations {
module_id: home, module_id: home,
solved_subs: roc_types::solved_types::Solved(subs), solved_subs: roc_types::solved_types::Solved(subs),
@ -3156,6 +3188,7 @@ fn build_pending_specializations<'a>(
layout_cache, layout_cache,
procs, procs,
problems, problems,
module_timing,
} }
} }
@ -3362,6 +3395,7 @@ fn run_task<'a>(
procs, procs,
layout_cache, layout_cache,
specializations_we_must_make, specializations_we_must_make,
module_timing,
} => Ok(make_specializations( } => Ok(make_specializations(
arena, arena,
module_id, module_id,
@ -3370,6 +3404,7 @@ fn run_task<'a>(
procs, procs,
layout_cache, layout_cache,
specializations_we_must_make, specializations_we_must_make,
module_timing,
)), )),
}?; }?;

View file

@ -11,6 +11,14 @@ extern "C" {
const REFCOUNT_1: usize = isize::MIN as usize; const REFCOUNT_1: usize = isize::MIN as usize;
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RocOrder {
Eq = 0,
Gt = 1,
Lt = 2,
}
//#[macro_export] //#[macro_export]
//macro_rules! roclist { //macro_rules! roclist {
// () => ( // () => (