Skip to content

Commit

Permalink
create and use more idiomatic APIs for LEM types (#902)
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurpaulino authored Nov 17, 2023
1 parent 0028b29 commit 1e4aea3
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 129 deletions.
119 changes: 43 additions & 76 deletions src/lem/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,14 +355,8 @@ fn run_cproc(cproc_sym: Symbol, arity: usize) -> Func {
let cproc_name = Var::new("cproc_name");
let cproc_out = vec![expr.clone(), env.clone(), cont.clone()];
let func_out = vec![expr, env.clone(), cont.clone()];
let err_block = Block {
ops: vec![],
ctrl: ctrl!(return (evaluated_args_cp, env, err)),
};
let def_block = Block {
ops: vec![],
ctrl: ctrl!(return (cproc, env, cont)),
};
let err_block = Block::ctrl(ctrl!(return (evaluated_args_cp, env, err)));
let def_block = Block::ctrl(ctrl!(return (cproc, env, cont)));
let mut cproc_inp = (0..arity)
.map(|i| Var(format!("x{i}").into()))
.collect::<Vec<_>>();
Expand All @@ -381,17 +375,14 @@ fn run_cproc(cproc_sym: Symbol, arity: usize) -> Func {
),
Op::EqTag(is_nil.clone(), evaluated_args.clone(), nil.clone()),
];
block = if i == 0 {
Block {
ops,
ctrl: Ctrl::If(is_nil.clone(), Box::new(block), Box::new(err_block.clone())),
}
} else {
Block {
ops,
ctrl: Ctrl::If(is_nil.clone(), Box::new(err_block.clone()), Box::new(block)),
}
}
block = Block {
ops,
ctrl: if i == 0 {
Ctrl::if_(is_nil.clone(), block, err_block.clone())
} else {
Ctrl::if_(is_nil.clone(), err_block.clone(), block)
},
};
}
if arity > 0 {
let ops = vec![
Expand All @@ -400,28 +391,24 @@ fn run_cproc(cproc_sym: Symbol, arity: usize) -> Func {
];
block = Block {
ops,
ctrl: Ctrl::If(is_nil.clone(), Box::new(err_block.clone()), Box::new(block)),
ctrl: Ctrl::if_(is_nil.clone(), err_block.clone(), block),
}
}

// MatchSymbol
let mut match_symbol_map = IndexMap::with_capacity(1);
match_symbol_map.insert(cproc_sym, block);
block = Block {
ops: vec![Op::Decons2(
[cproc_name.clone(), evaluated_args],
cproc.clone(),
)],
ctrl: Ctrl::MatchSymbol(
ctrl: Ctrl::match_symbol(
cproc_name,
match_symbol_map,
Some(Box::new(def_block.clone())),
vec![(cproc_sym, block)],
Some(def_block.clone()),
),
};

// MatchTag
let mut match_tag_map = IndexMap::with_capacity(1);
match_tag_map.insert(Tag::Expr(Cproc), block);
block = Block {
ops: if arity == 0 {
vec![]
Expand All @@ -432,7 +419,11 @@ fn run_cproc(cproc_sym: Symbol, arity: usize) -> Func {
op!(let nil = cast(nil, Expr::Nil)),
]
},
ctrl: Ctrl::MatchTag(cproc.clone(), match_tag_map, Some(Box::new(def_block))),
ctrl: Ctrl::match_tag(
cproc.clone(),
vec![(Tag::Expr(Cproc), block)],
Some(def_block),
),
};
let func_inp = vec![cproc, env, cont];
Func::new("run_cproc".into(), func_inp, 3, block).unwrap()
Expand Down Expand Up @@ -482,21 +473,12 @@ fn is_cproc(cprocs: &[(&Symbol, usize)]) -> Func {
op!(let nil = cast(nil, Expr::Nil)),
op!(let t = Symbol("t")),
];
let mut match_symbol_map = IndexMap::with_capacity(cprocs.len());
for (cproc, _) in cprocs {
match_symbol_map.insert(
(*cproc).clone(),
Block {
ops: vec![],
ctrl: ctrl!(return (t)),
},
);
}
let def = Some(Box::new(Block {
ops: vec![],
ctrl: ctrl!(return (nil)),
}));
let ctrl = Ctrl::MatchSymbol(head.clone(), match_symbol_map, def);
let match_symbol_cases = cprocs
.iter()
.map(|(cproc, _)| ((*cproc).clone(), Block::ctrl(ctrl!(return (t)))))
.collect();
let def = Some(Block::ctrl(ctrl!(return (nil))));
let ctrl = Ctrl::match_symbol(head.clone(), match_symbol_cases, def);
Func::new("is_cproc".into(), vec![head], 1, Block { ops, ctrl }).unwrap()
}
}
Expand Down Expand Up @@ -571,28 +553,16 @@ fn match_and_run_cproc(cprocs: &[(&Symbol, usize)]) -> Func {
let is_nil = Var::new("is_nil");
let cproc_out = vec![expr.clone(), env.clone(), cont.clone()];
let func_out = vec![expr, env.clone(), cont.clone(), Var::new("makethunk")];
let err_block = Block {
ops: vec![],
ctrl: ctrl!(return (evaluated_args_cp, env, err, errctrl)),
};
let err_block_from_cproc = Block {
ops: vec![],
ctrl: ctrl!(return (expr, env, err, errctrl)),
};
let ret_block_from_cproc = Block {
ops: vec![],
ctrl: ctrl!(return (expr, env, cont, ret)),
};
let mut check_cproc_error_map = IndexMap::with_capacity(2);
check_cproc_error_map.insert(Tag::Cont(Error), err_block_from_cproc);
check_cproc_error_map.insert(Tag::Cont(Terminal), ret_block_from_cproc);
let check_cproc_error_ctrl = Ctrl::MatchTag(
let err_block = Block::ctrl(ctrl!(return (evaluated_args_cp, env, err, errctrl)));
let err_block_from_cproc = Block::ctrl(ctrl!(return (expr, env, err, errctrl)));
let ret_block_from_cproc = Block::ctrl(ctrl!(return (expr, env, cont, ret)));
let check_cproc_error_ctrl = Ctrl::match_tag(
cont.clone(),
check_cproc_error_map,
Some(Box::new(Block {
ops: vec![],
ctrl: Ctrl::Return(func_out),
})),
vec![
(Tag::Cont(Error), err_block_from_cproc),
(Tag::Cont(Terminal), ret_block_from_cproc),
],
Some(Block::ctrl(Ctrl::Return(func_out))),
);
let mut match_symbol_map = IndexMap::with_capacity(cprocs.len());
for (cproc, arity) in cprocs {
Expand Down Expand Up @@ -620,17 +590,14 @@ fn match_and_run_cproc(cprocs: &[(&Symbol, usize)]) -> Func {
),
Op::EqTag(is_nil.clone(), evaluated_args.clone(), nil.clone()),
];
block = if i == 0 {
Block {
ops,
ctrl: Ctrl::If(is_nil.clone(), Box::new(block), Box::new(err_block.clone())),
}
} else {
Block {
ops,
ctrl: Ctrl::If(is_nil.clone(), Box::new(err_block.clone()), Box::new(block)),
}
}
block = Block {
ops,
ctrl: if i == 0 {
Ctrl::if_(is_nil.clone(), block, err_block.clone())
} else {
Ctrl::if_(is_nil.clone(), err_block.clone(), block)
},
};
}
if arity > 0 {
let ops = vec![
Expand All @@ -639,7 +606,7 @@ fn match_and_run_cproc(cprocs: &[(&Symbol, usize)]) -> Func {
];
block = Block {
ops,
ctrl: Ctrl::If(is_nil.clone(), Box::new(err_block.clone()), Box::new(block)),
ctrl: Ctrl::if_(is_nil.clone(), err_block.clone(), block),
}
}
match_symbol_map.insert(cproc.clone(), block);
Expand Down
81 changes: 34 additions & 47 deletions src/lem/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -692,47 +692,33 @@ mod tests {
lem::{Block, Ctrl, Op, Tag, Var},
state::lurk_sym,
tag::ExprTag::{Char, Num, Str},
Symbol,
};

#[inline]
fn mptr(name: &str) -> Var {
Var(name.into())
}

#[inline]
fn match_tag(i: Var, cases: Vec<(Tag, Block)>) -> Ctrl {
Ctrl::MatchTag(i, indexmap::IndexMap::from_iter(cases), None)
}

#[inline]
fn match_symbol(i: Var, cases: Vec<(Symbol, Block)>, def: Block) -> Ctrl {
Ctrl::MatchSymbol(i, indexmap::IndexMap::from_iter(cases), Some(Box::new(def)))
fn var(name: &str) -> Var {
Var::new(name)
}

#[test]
fn test_macros() {
let lemops = [
Op::Zero(mptr("foo"), Tag::Expr(Num)),
Op::Cons2(mptr("foo"), Tag::Expr(Char), [mptr("bar"), mptr("baz")]),
Op::Zero(var("foo"), Tag::Expr(Num)),
Op::Cons2(var("foo"), Tag::Expr(Char), [var("bar"), var("baz")]),
Op::Cons3(
mptr("foo"),
var("foo"),
Tag::Expr(Char),
[mptr("bar"), mptr("baz"), mptr("bazz")],
[var("bar"), var("baz"), var("bazz")],
),
Op::Cons4(
mptr("foo"),
var("foo"),
Tag::Expr(Char),
[mptr("bar"), mptr("baz"), mptr("bazz"), mptr("baxx")],
),
Op::Decons2([mptr("foo"), mptr("goo")], mptr("aaa")),
Op::Decons3([mptr("foo"), mptr("goo"), mptr("moo")], mptr("aaa")),
Op::Decons4(
[mptr("foo"), mptr("goo"), mptr("moo"), mptr("noo")],
mptr("aaa"),
[var("bar"), var("baz"), var("bazz"), var("baxx")],
),
Op::Hide(mptr("bar"), mptr("baz"), mptr("bazz")),
Op::Open(mptr("bar"), mptr("baz"), mptr("bazz")),
Op::Decons2([var("foo"), var("goo")], var("aaa")),
Op::Decons3([var("foo"), var("goo"), var("moo")], var("aaa")),
Op::Decons4([var("foo"), var("goo"), var("moo"), var("noo")], var("aaa")),
Op::Hide(var("bar"), var("baz"), var("bazz")),
Op::Open(var("bar"), var("baz"), var("bazz")),
];
let lemops_macro = vec![
op!(let foo: Expr::Num),
Expand All @@ -750,7 +736,7 @@ mod tests {
assert!(lemops[i] == lemops_macro[i]);
}

let ret = Ctrl::Return(vec![mptr("bar"), mptr("baz"), mptr("bazz")]);
let ret = Ctrl::Return(vec![var("bar"), var("baz"), var("bazz")]);
let block = Block {
ops: lemops_macro,
ctrl: ret,
Expand Down Expand Up @@ -785,34 +771,35 @@ mod tests {
}
});
assert!(
foo == match_tag(
mptr("www"),
foo == Ctrl::match_tag(
var("www"),
vec![
(
Tag::Expr(Num),
Block {
ops: vec![],
ctrl: Ctrl::Return(vec![mptr("foo"), mptr("foo"), mptr("foo")]),
ctrl: Ctrl::Return(vec![var("foo"), var("foo"), var("foo")]),
}
),
(
Tag::Expr(Str),
Block {
ops: vec![Op::Zero(mptr("foo"), Tag::Expr(Num))],
ctrl: Ctrl::Return(vec![mptr("foo"), mptr("foo"), mptr("foo")]),
ops: vec![Op::Zero(var("foo"), Tag::Expr(Num))],
ctrl: Ctrl::Return(vec![var("foo"), var("foo"), var("foo")]),
}
),
(
Tag::Expr(Char),
Block {
ops: vec![
Op::Zero(mptr("foo"), Tag::Expr(Num)),
Op::Zero(mptr("goo"), Tag::Expr(Char))
Op::Zero(var("foo"), Tag::Expr(Num)),
Op::Zero(var("goo"), Tag::Expr(Char))
],
ctrl: Ctrl::Return(vec![mptr("foo"), mptr("goo"), mptr("goo")]),
ctrl: Ctrl::Return(vec![var("foo"), var("goo"), var("goo")]),
}
)
]
],
None,
)
);

Expand All @@ -832,31 +819,31 @@ mod tests {
);

assert!(
moo == match_symbol(
mptr("www"),
moo == Ctrl::match_symbol(
var("www"),
vec![
(
lurk_sym("nil"),
Block {
ops: vec![],
ctrl: Ctrl::Return(vec![mptr("foo"), mptr("foo"), mptr("foo")]),
ctrl: Ctrl::Return(vec![var("foo"), var("foo"), var("foo")]),
}
),
(
lurk_sym("cons"),
Block {
ops: vec![
Op::Zero(mptr("foo"), Tag::Expr(Num)),
Op::Zero(mptr("goo"), Tag::Expr(Char))
Op::Zero(var("foo"), Tag::Expr(Num)),
Op::Zero(var("goo"), Tag::Expr(Char))
],
ctrl: Ctrl::Return(vec![mptr("foo"), mptr("goo"), mptr("goo")]),
ctrl: Ctrl::Return(vec![var("foo"), var("goo"), var("goo")]),
}
)
],
Block {
ops: vec![Op::Zero(mptr("xoo"), Tag::Expr(Str))],
ctrl: Ctrl::Return(vec![mptr("xoo"), mptr("xoo"), mptr("xoo")]),
}
Some(Block {
ops: vec![Op::Zero(var("xoo"), Tag::Expr(Str))],
ctrl: Ctrl::Return(vec![var("xoo"), var("xoo"), var("xoo")]),
})
)
);
}
Expand Down
33 changes: 27 additions & 6 deletions src/lem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,16 @@ impl Var {
pub fn name(&self) -> &AString {
&self.0
}

#[inline]
pub fn new(name: &str) -> Self {
Self(name.into())
}

fn make_unique(&self, uniq: &mut usize) -> Var {
*uniq += 1;
Var(format!("{}#{}", self.name(), uniq).into())
}
}

/// A block is a sequence of operations followed by a control. Each block
Expand Down Expand Up @@ -780,16 +790,27 @@ impl Block {
};
Ok(Block { ops, ctrl })
}

/// Creates a `Block` with an empty vector of `Op`s
#[inline]
fn ctrl(ctrl: Ctrl) -> Block {
Block { ops: vec![], ctrl }
}
}

impl Var {
impl Ctrl {
#[inline]
pub fn new(name: &str) -> Self {
Self(name.into())
fn if_(v: Var, true_block: Block, false_block: Block) -> Ctrl {
Ctrl::If(v, true_block.into(), false_block.into())
}

fn make_unique(&self, uniq: &mut usize) -> Var {
*uniq += 1;
Var(format!("{}#{}", self.name(), uniq).into())
#[inline]
fn match_tag(v: Var, cases: Vec<(Tag, Block)>, def: Option<Block>) -> Ctrl {
Ctrl::MatchTag(v, IndexMap::from_iter(cases), def.map(|b| b.into()))
}

#[inline]
fn match_symbol(v: Var, cases: Vec<(Symbol, Block)>, def: Option<Block>) -> Ctrl {
Ctrl::MatchSymbol(v, IndexMap::from_iter(cases), def.map(|b| b.into()))
}
}

1 comment on commit 1e4aea3

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmarks

Table of Contents

Overview

This benchmark report shows the Fibonacci GPU benchmark.
NVIDIA GeForce RTX 4070
AMD Ryzen 9 3950X 16-Core Processor
125.711 GB RAM

Benchmark Results

LEM Fibonacci Prove - rc = 100

fib-ref=0028b2902d166ee96ad27d2935b9a7542ff6d25e fib-ref=1e4aea319faf4157d03c9a415c498437dad79221
num-100 3.95 s (✅ 1.00x) 3.95 s (✅ 1.00x slower)
num-200 8.18 s (✅ 1.00x) 8.13 s (✅ 1.01x faster)

LEM Fibonacci Prove - rc = 600

fib-ref=0028b2902d166ee96ad27d2935b9a7542ff6d25e fib-ref=1e4aea319faf4157d03c9a415c498437dad79221
num-100 3.06 s (✅ 1.00x) 3.04 s (✅ 1.01x faster)
num-200 6.99 s (✅ 1.00x) 6.98 s (✅ 1.00x faster)

Made with criterion-table

Please sign in to comment.