diff --git a/examples/sort/bitonic/main.hvm b/examples/sort/bitonic/main.hvm deleted file mode 100644 index ed89e3ac..00000000 --- a/examples/sort/bitonic/main.hvm +++ /dev/null @@ -1,36 +0,0 @@ -// Atomic Swapper (HVM builtin) -//(U60.swap 0 a b) = (Both a b) -//(U60.swap n a b) = (Both b a) - -// Swaps distant values in parallel; corresponds to a Red Box -(Warp s (Leaf a) (Leaf b)) = (U60.swap (^ (> a b) s) (Leaf a) (Leaf b)) -(Warp s (Both a b) (Both c d)) = (Join (Warp s a c) (Warp s b d)) - -// Rebuilds the warped tree in the original order -(Join (Both a b) (Both c d)) = (Both (Both a c) (Both b d)) - -// Recursively warps each sub-tree; corresponds to a Blue/Green Box -(Flow s (Leaf a)) = (Leaf a) -(Flow s (Both a b)) = (Down s (Warp s a b)) - -// Propagates Flow downwards -(Down s (Leaf a)) = (Leaf a) -(Down s (Both a b)) = (Both (Flow s a) (Flow s b)) - -// Bitonic Sort -(Sort s (Leaf a)) = (Leaf a) -(Sort s (Both a b)) = (Flow s (Both (Sort 0 a) (Sort 1 b))) - -// Generates a tree of depth `n` -(Gen 0 x) = (Leaf x) -(Gen n x) = let m = (- n 1); (Both (Gen m (* x 2)) (Gen m (+ (* x 2) 1))) - -// Reverses a tree -(Rev (Leaf x)) = (Leaf x) -(Rev (Both a b)) = (Both (Rev b) (Rev a)) - -// Sums a tree -(Sum (Leaf x)) = x -(Sum (Both a b)) = (+ (Sum a) (Sum b)) - -(Main n) = (Sum (Sort 0 (Rev (Gen n 0)))) diff --git a/src/compiler/compile.rs b/src/compiler/compile.rs index 98951c45..2cb29c32 100644 --- a/src/compiler/compile.rs +++ b/src/compiler/compile.rs @@ -394,14 +394,19 @@ pub fn build_function_rule_rhs( free : &mut Vec>, nams : &mut u64, dups : &mut HashMap, + dupf : u64, glob : u64, ) -> (String, String) { if let Some(got) = dups.get(&glob) { return got.clone(); } else { - let coln = fresh(nams, "col"); let name = fresh(nams, "dup"); - line(code, tab + 1, &format!("let {} = gen_dup(ctx.heap, ctx.tid);", coln)); + let coln = fresh(nams, "col"); + if dupf != 0xFFFFFFFF { + line(code, tab + 1, &format!("let {} = {};", coln, dupf)); + } else { + line(code, tab + 1, &format!("let {} = gen_dup(ctx.heap, ctx.tid);", coln)); + } line(code, tab + 1, &format!("let {} = {};", name, alloc_node(free, 3))); line(code, tab, &format!("link(ctx.heap, {} + 0, Era());", name)); // FIXME: remove when possible (same as above) line(code, tab, &format!("link(ctx.heap, {} + 1, Era());", name)); // FIXME: remove when possible (same as above) @@ -457,11 +462,11 @@ pub fn build_function_rule_rhs( return format!("Var({})", alloc_lam(code, tab, free, nams, lams, *glob)); } runtime::DP0 => { - let (coln, name) = alloc_dup(code, tab, free, nams, dups, *glob); + let (coln, name) = alloc_dup(code, tab, free, nams, dups, 0, *glob); return format!("Dp0({}, {})", coln, name); } runtime::DP1 => { - let (coln, name) = alloc_dup(code, tab, free, nams, dups, *glob); + let (coln, name) = alloc_dup(code, tab, free, nams, dups, 0, *glob); return format!("Dp1({}, {})", coln, name); } _ => { @@ -469,7 +474,7 @@ pub fn build_function_rule_rhs( } } } - runtime::Core::Dup { eras, glob, expr, body } => { + runtime::Core::Dup { dupf, eras, glob, expr, body } => { let copy = fresh(nams, "cpy"); let dup0 = fresh(nams, "dp0"); let dup1 = fresh(nams, "dp1"); @@ -484,7 +489,7 @@ pub fn build_function_rule_rhs( line(code, tab + 1, &format!("{} = {};", dup1, copy)); line(code, tab + 0, "} else {"); } - let (coln, name) = alloc_dup(code, tab, &mut vec![], nams, dups, *glob); + let (coln, name) = alloc_dup(code, tab, &mut vec![], nams, dups, *dupf, *glob); if eras.0 { line(code, tab + 1, &format!("link(ctx.heap, {} + 0, Era());", name)); } @@ -504,12 +509,16 @@ pub fn build_function_rule_rhs( vars.pop(); body } - runtime::Core::Sup { val0, val1 } => { + runtime::Core::Sup { dupf, val0, val1 } => { let name = fresh(nams, "sup"); let val0 = build_term(book, code, tab, free, vars, nams, lams, dups, val0); let val1 = build_term(book, code, tab, free, vars, nams, lams, dups, val1); let coln = fresh(nams, "col"); - line(code, tab + 1, &format!("let {} = gen_dup(ctx.heap, ctx.tid);", coln)); + if *dupf != 0xFFFFFFFF { + line(code, tab + 1, &format!("let {} = {};", coln, dupf)); + } else { + line(code, tab + 1, &format!("let {} = gen_dup(ctx.heap, ctx.tid);", coln)); + } line(code, tab, &format!("let {} = {};", name, alloc_node(free, 2))); line(code, tab, &format!("link(ctx.heap, {} + 0, {});", name, val0)); line(code, tab, &format!("link(ctx.heap, {} + 1, {});", name, val1)); diff --git a/src/language/readback.rs b/src/language/readback.rs index 0c6ea054..168be8ad 100644 --- a/src/language/readback.rs +++ b/src/language/readback.rs @@ -140,11 +140,12 @@ pub fn as_term(heap: &Heap, prog: &Program, host: u64) -> Box { @@ -312,11 +313,12 @@ pub fn as_linear_term(heap: &Heap, prog: &Program, host: u64) -> Box { + language::syntax::Term::Sup { dupf: _, val0, val1 } => { register(book, val0, false); register(book, val1, false); } @@ -295,7 +295,7 @@ pub fn sanitize_rule(rule: &language::syntax::Rule) -> Result { + language::syntax::Term::Dup { dupf, expr, body, nam0, nam1 } => { let is_global_0 = runtime::get_global_name_misc(nam0).is_some(); let is_global_1 = runtime::get_global_name_misc(nam1).is_some(); if is_global_0 && runtime::get_global_name_misc(nam0) != Some(runtime::DP0) { @@ -334,15 +334,17 @@ pub fn sanitize_rule(rule: &language::syntax::Rule) -> Result { + language::syntax::Term::Sup { dupf, val0, val1 } => { + let dupf = dupf.clone(); let val0 = sanitize_term(val0, lhs, tbl, ctx)?; let val1 = sanitize_term(val1, lhs, tbl, ctx)?; - let term = language::syntax::Term::Sup { val0, val1 }; + let term = language::syntax::Term::Sup { dupf, val0, val1 }; Box::new(term) } language::syntax::Term::Let { name, expr, body } => { @@ -459,6 +461,7 @@ pub fn sanitize_rule(rule: &language::syntax::Rule) -> Result Result { + language::syntax::Term::Dup { dupf: _, nam0, nam1, expr, body } => { subst(&mut *expr, sub_name, value); if nam0 != sub_name && nam1 != sub_name { subst(&mut *body, sub_name, value); } } - language::syntax::Term::Sup { val0, val1 } => { + language::syntax::Term::Sup { dupf: _, val0, val1 } => { subst(&mut *val0, sub_name, value); subst(&mut *val1, sub_name, value); } diff --git a/src/language/syntax.rs b/src/language/syntax.rs index fcfe1101..832f1c93 100644 --- a/src/language/syntax.rs +++ b/src/language/syntax.rs @@ -11,8 +11,8 @@ use crate::runtime::data::f60; #[derive(Clone, Debug)] pub enum Term { Var { name: String }, // TODO: add `global: bool` - Dup { nam0: String, nam1: String, expr: Box, body: Box }, - Sup { val0: Box, val1: Box }, + Dup { dupf: String, nam0: String, nam1: String, expr: Box, body: Box }, + Sup { dupf: String, val0: Box, val1: Box }, Let { name: String, expr: Box, body: Box }, Lam { name: String, body: Box }, App { func: Box, argm: Box }, @@ -133,8 +133,8 @@ impl std::fmt::Display for Term { } match self { Self::Var { name } => write!(f, "{}", name), - Self::Dup { nam0, nam1, expr, body } => write!(f, "dup {} {} = {}; {}", nam0, nam1, expr, body), - Self::Sup { val0, val1 } => write!(f, "{{{} {}}}", val0, val1), + Self::Dup { dupf, nam0, nam1, expr, body } => write!(f, "dup #{}{{{} {}}} = {}; {}", dupf, nam0, nam1, expr, body), + Self::Sup { dupf, val0, val1 } => write!(f, "#{}{{{} {}}}", dupf, val0, val1), Self::Let { name, expr, body } => write!(f, "let {} = {}; {}", name, expr, body), Self::Lam { name, body } => write!(f, "λ{} {}", name, body), Self::App { func, argm } => { @@ -207,13 +207,35 @@ pub fn parse_dup(state: HOPA::State) -> HOPA::Answer>> { HOPA::do_there_take_exact("dup "), Box::new(|state| { let (state, _) = HOPA::force_there_take_exact("dup ", state)?; + let (state, _) = HOPA::force_there_take_exact("{", state)?; + let (state, nam0) = HOPA::there_nonempty_name(state)?; + let (state, nam1) = HOPA::there_nonempty_name(state)?; + let (state, _) = HOPA::force_there_take_exact("}", state)?; + let (state, _) = HOPA::force_there_take_exact("=", state)?; + let (state, expr) = parse_term(state)?; + let (state, _) = HOPA::there_take_exact(";", state)?; + let (state, body) = parse_term(state)?; + Ok((state, Box::new(Term::Dup { dupf: "".to_string(), nam0, nam1, expr, body }))) + }), + state, + ); +} + +pub fn parse_dup_tag(state: HOPA::State) -> HOPA::Answer>> { + return HOPA::guard( + HOPA::do_there_take_exact("dup #"), + Box::new(|state| { + let (state, _) = HOPA::force_there_take_exact("dup #", state)?; + let (state, dupf) = HOPA::there_name(state)?; + let (state, _) = HOPA::force_there_take_exact("{", state)?; let (state, nam0) = HOPA::there_nonempty_name(state)?; let (state, nam1) = HOPA::there_nonempty_name(state)?; + let (state, _) = HOPA::force_there_take_exact("}", state)?; let (state, _) = HOPA::force_there_take_exact("=", state)?; let (state, expr) = parse_term(state)?; let (state, _) = HOPA::there_take_exact(";", state)?; let (state, body) = parse_term(state)?; - Ok((state, Box::new(Term::Dup { nam0, nam1, expr, body }))) + Ok((state, Box::new(Term::Dup { dupf, nam0, nam1, expr, body }))) }), state, ); @@ -223,11 +245,28 @@ pub fn parse_sup(state: HOPA::State) -> HOPA::Answer>> { HOPA::guard( HOPA::do_there_take_exact("{"), Box::new(move |state| { + let (state, dupf) = HOPA::there_name(state)?; + let (state, _) = HOPA::force_there_take_exact("{", state)?; + let (state, val0) = parse_term(state)?; + let (state, val1) = parse_term(state)?; + let (state, _) = HOPA::force_there_take_exact("}", state)?; + Ok((state, Box::new(Term::Sup { dupf, val0, val1 }))) + }), + state, + ) +} + +pub fn parse_sup_tag(state: HOPA::State) -> HOPA::Answer>> { + HOPA::guard( + HOPA::do_there_take_exact("#"), + Box::new(move |state| { + let (state, _) = HOPA::force_there_take_exact("#", state)?; + let (state, dupf) = HOPA::there_name(state)?; let (state, _) = HOPA::force_there_take_exact("{", state)?; let (state, val0) = parse_term(state)?; let (state, val1) = parse_term(state)?; let (state, _) = HOPA::force_there_take_exact("}", state)?; - Ok((state, Box::new(Term::Sup { val0, val1 }))) + Ok((state, Box::new(Term::Sup { dupf, val0, val1 }))) }), state, ) @@ -554,12 +593,14 @@ pub fn parse_bng(state: HOPA::State) -> HOPA::Answer>> { pub fn parse_term(state: HOPA::State) -> HOPA::Answer> { HOPA::attempt("Term", &[ Box::new(parse_let), + Box::new(parse_dup_tag), Box::new(parse_dup), Box::new(parse_lam), Box::new(parse_ctr), Box::new(parse_op2), Box::new(parse_app), Box::new(parse_sup), + Box::new(parse_sup_tag), Box::new(parse_num), Box::new(parse_sym_sugar), Box::new(parse_chr_sugar), diff --git a/src/runtime/base/program.rs b/src/runtime/base/program.rs index 75c6fae7..fba5810b 100644 --- a/src/runtime/base/program.rs +++ b/src/runtime/base/program.rs @@ -8,8 +8,8 @@ use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; pub enum Core { Var { bidx: u64 }, Glo { glob: u64, misc: u64 }, - Dup { eras: (bool, bool), glob: u64, expr: Box, body: Box }, - Sup { val0: Box, val1: Box }, + Dup { dupf: u64, eras: (bool, bool), glob: u64, expr: Box, body: Box }, + Sup { dupf: u64, val0: Box, val1: Box }, Let { expr: Box, body: Box }, Lam { eras: bool, glob: u64, body: Box }, App { func: Box, argm: Box }, @@ -339,21 +339,23 @@ pub fn term_to_core(book: &language::rulebook::RuleBook, term: &language::syntax } } } - language::syntax::Term::Dup { nam0, nam1, expr, body } => { + language::syntax::Term::Dup { dupf, nam0, nam1, expr, body } => { let eras = (nam0 == "*", nam1 == "*"); let glob = if get_global_name_misc(nam0).is_some() { hash(&nam0[2..].to_string()) } else { 0 }; + let dupf = dupf.parse::().unwrap_or(0xFFFFFFFF); let expr = Box::new(convert_term(expr, book, depth + 0, vars)); vars.push(nam0.clone()); vars.push(nam1.clone()); let body = Box::new(convert_term(body, book, depth + 2, vars)); vars.pop(); vars.pop(); - Core::Dup { eras, glob, expr, body } + Core::Dup { dupf, eras, glob, expr, body } } - language::syntax::Term::Sup { val0, val1 } => { + language::syntax::Term::Sup { dupf, val0, val1 } => { + let dupf = dupf.parse::().unwrap_or(0xFFFFFFFF); let val0 = Box::new(convert_term(val0, book, depth + 0, vars)); let val1 = Box::new(convert_term(val1, book, depth + 0, vars)); - Core::Sup { val0, val1 } + Core::Sup { dupf, val0, val1 } } language::syntax::Term::Lam { name, body } => { let glob = if get_global_name_misc(name).is_some() { hash(name) } else { 0 }; @@ -422,13 +424,12 @@ pub fn build_body(term: &Core, free_vars: u64) -> RuleBody { return targ; } } - fn alloc_dup(dups: &mut HashMap, nodes: &mut Vec, links: &mut Vec<(u64, u64, RuleBodyCell)>, dupk: &mut u64, glob: u64) -> (u64, u64) { + fn alloc_dup(dups: &mut HashMap, nodes: &mut Vec, links: &mut Vec<(u64, u64, RuleBodyCell)>, dupf: u64, dupk: &mut u64, glob: u64) -> (u64, u64) { if let Some(got) = dups.get(&glob) { return got.clone(); } else { - let dupc = *dupk; let targ = nodes.len() as u64; - *dupk += 1; + let dupc = if dupf != 0xFFFFFFFF { dupf } else { *dupk += 1; *dupk - 1 }; nodes.push(vec![RuleBodyCell::Val { value: 0 }; 3]); links.push((targ, 0, RuleBodyCell::Val { value: Era() })); links.push((targ, 1, RuleBodyCell::Val { value: Era() })); @@ -462,11 +463,11 @@ pub fn build_body(term: &Core, free_vars: u64) -> RuleBody { return RuleBodyCell::Ptr { value: Var(0), targ, slot: 0 }; } DP0 => { - let (targ, dupc) = alloc_dup(dups, nodes, links, dupk, *glob); + let (targ, dupc) = alloc_dup(dups, nodes, links, 0, dupk, *glob); return RuleBodyCell::Ptr { value: Dp0(dupc, 0), targ, slot: 0 }; } DP1 => { - let (targ, dupc) = alloc_dup(dups, nodes, links, dupk, *glob); + let (targ, dupc) = alloc_dup(dups, nodes, links, 0, dupk, *glob); return RuleBodyCell::Ptr { value: Dp1(dupc, 0), targ, slot: 0 }; } _ => { @@ -474,11 +475,10 @@ pub fn build_body(term: &Core, free_vars: u64) -> RuleBody { } } } - Core::Dup { eras: _, glob, expr, body } => { - let (targ, dupc) = alloc_dup(dups, nodes, links, dupk, *glob); + Core::Dup { dupf, eras: _, glob, expr, body } => { + let (targ, dupc) = alloc_dup(dups, nodes, links, *dupf, dupk, *glob); let expr = gen_elems(expr, dupk, vars, lams, dups, nodes, links); links.push((targ, 2, expr)); - //let dupc = 0; // FIXME remove vars.push(RuleBodyCell::Ptr { value: Dp0(dupc, 0), targ, slot: 0 }); vars.push(RuleBodyCell::Ptr { value: Dp1(dupc, 0), targ, slot: 0 }); let body = gen_elems(body, dupk, vars, lams, dups, nodes, links); @@ -486,16 +486,14 @@ pub fn build_body(term: &Core, free_vars: u64) -> RuleBody { vars.pop(); body } - Core::Sup { val0, val1 } => { - let dupc = *dupk; + Core::Sup { dupf, val0, val1 } => { let targ = nodes.len() as u64; - *dupk += 1; + let dupc = if *dupf != 0xFFFFFFFF { *dupf } else { *dupk += 1; *dupk - 1 }; nodes.push(vec![RuleBodyCell::Val { value: 0 }; 2]); let val0 = gen_elems(val0, dupk, vars, lams, dups, nodes, links); links.push((targ, 0, val0)); let val1 = gen_elems(val1, dupk, vars, lams, dups, nodes, links); links.push((targ, 1, val1)); - //let dupc = 0; // FIXME remove RuleBodyCell::Ptr { value: Sup(dupc, 0), targ, slot: 0 } } Core::Let { expr, body } => {