Nearly finished the bjit2jit compiler.
This commit is contained in:
parent
41b0b3b7fc
commit
4d5a4ef865
6 changed files with 305 additions and 216 deletions
|
@ -96,7 +96,7 @@ enum BlkASTNode {
|
|||
},
|
||||
Literal {
|
||||
value: f64,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
impl BlkASTNode {
|
||||
|
@ -169,13 +169,7 @@ impl BlkASTNode {
|
|||
lbl: &str,
|
||||
childs: Vec<(Option<String>, BlkASTRef)>,
|
||||
) -> BlkASTRef {
|
||||
Rc::new(BlkASTNode::Node {
|
||||
id,
|
||||
out,
|
||||
typ: typ.to_string(),
|
||||
lbl: lbl.to_string(),
|
||||
childs,
|
||||
})
|
||||
Rc::new(BlkASTNode::Node { id, out, typ: typ.to_string(), lbl: lbl.to_string(), childs })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,6 +181,9 @@ pub enum BlkJITCompileError {
|
|||
ASTMissingOutputLabel(usize),
|
||||
NoTmpVarForOutput(usize, String),
|
||||
BadLiteralNumber(String),
|
||||
NodeWithoutID(String),
|
||||
UnknownType(String),
|
||||
TooManyInputs(String, usize),
|
||||
}
|
||||
|
||||
pub struct Block2JITCompiler {
|
||||
|
@ -260,9 +257,7 @@ impl Block2JITCompiler {
|
|||
Err(BlkJITCompileError::BadTree(node.clone()))
|
||||
}
|
||||
}
|
||||
"value" => {
|
||||
Ok(BlkASTNode::new_literal(&node.0.borrow().lbl)?)
|
||||
}
|
||||
"value" => Ok(BlkASTNode::new_literal(&node.0.borrow().lbl)?),
|
||||
"set" => {
|
||||
if let Some((_in, out, first)) = node.first_child() {
|
||||
let out = if out.len() > 0 { Some(out) } else { None };
|
||||
|
@ -283,7 +278,6 @@ impl Block2JITCompiler {
|
|||
area.push(BlkASTNode::new_get(0, &tmp_var));
|
||||
self.store_idout_var(id, "", &tmp_var);
|
||||
Ok(BlkASTNode::new_area(area))
|
||||
|
||||
} else {
|
||||
Err(BlkJITCompileError::BadTree(node.clone()))
|
||||
}
|
||||
|
@ -327,11 +321,7 @@ impl Block2JITCompiler {
|
|||
&tmp_var,
|
||||
BlkASTNode::new_get(0, &format!("%{}", i)),
|
||||
));
|
||||
self.store_idout_var(
|
||||
id,
|
||||
&oname,
|
||||
&tmp_var,
|
||||
);
|
||||
self.store_idout_var(id, &oname, &tmp_var);
|
||||
} else {
|
||||
return Err(BlkJITCompileError::NoOutputAtIdx(optype.to_string(), i));
|
||||
}
|
||||
|
@ -371,20 +361,44 @@ impl Block2JITCompiler {
|
|||
stmt.push(self.bjit2jit(&c)?);
|
||||
}
|
||||
Ok(stmts(&stmt[..]))
|
||||
},
|
||||
}
|
||||
BlkASTNode::Set { var, expr } => {
|
||||
let e = self.bjit2jit(&expr)?;
|
||||
Ok(assign(var, e))
|
||||
}
|
||||
BlkASTNode::Get { id, var: varname } => {
|
||||
Ok(var(varname))
|
||||
BlkASTNode::Get { id, var: varname } => Ok(var(varname)),
|
||||
BlkASTNode::Node { id, out, typ, lbl, childs } => match &typ[..] {
|
||||
"if" => Err(BlkJITCompileError::UnknownError),
|
||||
"zero" => Ok(literal(0.0)),
|
||||
node => {
|
||||
if *id == 0 {
|
||||
return Err(BlkJITCompileError::NodeWithoutID(typ.to_string()));
|
||||
}
|
||||
|
||||
let lang = self.lang.clone();
|
||||
|
||||
let mut args = vec![];
|
||||
|
||||
if let Some(inputs) = lang.borrow().get_type_inputs(typ) {
|
||||
if childs.len() > inputs.len() {
|
||||
return Err(BlkJITCompileError::TooManyInputs(typ.to_string(), *id));
|
||||
}
|
||||
|
||||
for input_name in inputs.iter() {
|
||||
for (inp, c) in childs.iter() {
|
||||
if inp == input_name {
|
||||
args.push(self.bjit2jit(&c)?);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(BlkJITCompileError::UnknownType(typ.to_string()));
|
||||
}
|
||||
|
||||
Ok(call(typ, *id as u64, &args[..]))
|
||||
}
|
||||
},
|
||||
BlkASTNode::Node { id, out, typ, lbl, childs } => {
|
||||
Err(BlkJITCompileError::UnknownError)
|
||||
}
|
||||
BlkASTNode::Literal { value } => {
|
||||
Ok(literal(*value))
|
||||
}
|
||||
BlkASTNode::Literal { value } => Ok(literal(*value)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,21 +430,23 @@ mod test {
|
|||
};
|
||||
}
|
||||
|
||||
use synfx_dsp_jit::{get_standard_library, DSPNodeContext, JIT, ASTFun, DSPFunction};
|
||||
use synfx_dsp_jit::{get_standard_library, ASTFun, DSPFunction, DSPNodeContext, JIT};
|
||||
|
||||
fn new_jit_fun<F: FnMut(&mut BlockFun)>(mut f: F) -> (Rc<RefCell<DSPNodeContext>>, Box<DSPFunction>) {
|
||||
fn new_jit_fun<F: FnMut(&mut BlockFun)>(
|
||||
mut f: F,
|
||||
) -> (Rc<RefCell<DSPNodeContext>>, Box<DSPFunction>) {
|
||||
use crate::block_compiler::{BlkJITCompileError, Block2JITCompiler};
|
||||
use crate::blocklang::BlockFun;
|
||||
use crate::blocklang_def;
|
||||
|
||||
let lang = blocklang_def::setup_hxdsp_block_language();
|
||||
let lib = get_standard_library();
|
||||
let lang = blocklang_def::setup_hxdsp_block_language(lib.clone());
|
||||
let mut bf = BlockFun::new(lang.clone());
|
||||
|
||||
f(&mut bf);
|
||||
|
||||
let mut compiler = Block2JITCompiler::new(bf.block_language());
|
||||
let ast = compiler.compile(&bf).expect("blk2jit compiles");
|
||||
let lib = get_standard_library();
|
||||
let ctx = DSPNodeContext::new_ref();
|
||||
let jit = JIT::new(lib, ctx.clone());
|
||||
let mut fun = jit.compile(ASTFun::new(ast)).expect("jit compiles");
|
||||
|
@ -440,7 +456,6 @@ mod test {
|
|||
(ctx, fun)
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn check_blocklang_sig1() {
|
||||
let (ctx, mut fun) = new_jit_fun(|bf| {
|
||||
|
@ -460,4 +475,36 @@ mod test {
|
|||
ctx.borrow_mut().free();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_blocklang_accum_shift() {
|
||||
let (ctx, mut fun) = new_jit_fun(|bf| {
|
||||
bf.instanciate_at(0, 1, 1, "accum", None);
|
||||
bf.shift_port(0, 1, 1, 1, false);
|
||||
bf.instanciate_at(0, 0, 2, "value", Some("0.01".to_string()));
|
||||
bf.instanciate_at(0, 0, 1, "get", Some("*reset".to_string()));
|
||||
});
|
||||
|
||||
fun.exec_2in_2out(0.0, 0.0);
|
||||
fun.exec_2in_2out(0.0, 0.0);
|
||||
fun.exec_2in_2out(0.0, 0.0);
|
||||
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0);
|
||||
assert_float_eq!(ret, 0.04);
|
||||
|
||||
let reset_idx = ctx.borrow().get_persistent_variable_index_by_name("*reset").unwrap();
|
||||
fun.access_persistent_var(reset_idx).map(|reset| *reset = 1.0);
|
||||
|
||||
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0);
|
||||
assert_float_eq!(ret, 0.0);
|
||||
|
||||
fun.access_persistent_var(reset_idx).map(|reset| *reset = 0.0);
|
||||
|
||||
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0);
|
||||
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0);
|
||||
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0);
|
||||
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0);
|
||||
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0);
|
||||
assert_float_eq!(ret, 0.05);
|
||||
|
||||
ctx.borrow_mut().free();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -907,8 +907,13 @@ impl BlockLanguage {
|
|||
Some(&typ.outputs)
|
||||
}
|
||||
|
||||
pub fn get_type_inputs(&self, typ: &str) -> Option<&[Option<String>]> {
|
||||
let typ = self.types.get(typ)?;
|
||||
Some(&typ.inputs)
|
||||
}
|
||||
|
||||
pub fn get_output_name_at_index(&self, typ: &str, idx: usize) -> Option<String> {
|
||||
let outs = self.get_type_outputs(typ)?;
|
||||
if let Some(outs) = self.get_type_outputs(typ) {
|
||||
let mut i = 0;
|
||||
for o in outs.iter() {
|
||||
if let Some(outname) = o {
|
||||
|
@ -918,6 +923,7 @@ impl BlockLanguage {
|
|||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
|
|
@ -2,11 +2,14 @@
|
|||
// This file is a part of HexoDSP. Released under GPL-3.0-or-later.
|
||||
// See README.md and COPYING for details.
|
||||
|
||||
use crate::blocklang::{BlockLanguage, BlockUserInput, BlockType};
|
||||
use crate::blocklang::{BlockLanguage, BlockType, BlockUserInput};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use synfx_dsp_jit::DSPNodeTypeLibrary;
|
||||
|
||||
pub fn setup_hxdsp_block_language() -> Rc<RefCell<BlockLanguage>> {
|
||||
pub fn setup_hxdsp_block_language(
|
||||
dsp_lib: Rc<RefCell<DSPNodeTypeLibrary>>,
|
||||
) -> Rc<RefCell<BlockLanguage>> {
|
||||
let mut lang = BlockLanguage::new();
|
||||
|
||||
lang.define(BlockType {
|
||||
|
@ -17,7 +20,9 @@ pub fn setup_hxdsp_block_language() -> Rc<RefCell<BlockLanguage>> {
|
|||
outputs: vec![Some("".to_string())],
|
||||
area_count: 0,
|
||||
user_input: BlockUserInput::None,
|
||||
description: "A phasor, returns a saw tooth wave to scan through things or use as modulator.".to_string(),
|
||||
description:
|
||||
"A phasor, returns a saw tooth wave to scan through things or use as modulator."
|
||||
.to_string(),
|
||||
color: 2,
|
||||
});
|
||||
|
||||
|
@ -57,18 +62,6 @@ pub fn setup_hxdsp_block_language() -> Rc<RefCell<BlockLanguage>> {
|
|||
color: 1,
|
||||
});
|
||||
|
||||
lang.define(BlockType {
|
||||
category: "literals".to_string(),
|
||||
name: "SR".to_string(),
|
||||
rows: 1,
|
||||
inputs: vec![],
|
||||
outputs: vec![Some("".to_string())],
|
||||
area_count: 0,
|
||||
user_input: BlockUserInput::None,
|
||||
description: "The sample rate".to_string(),
|
||||
color: 1,
|
||||
});
|
||||
|
||||
lang.define(BlockType {
|
||||
category: "literals".to_string(),
|
||||
name: "value".to_string(),
|
||||
|
@ -101,7 +94,8 @@ pub fn setup_hxdsp_block_language() -> Rc<RefCell<BlockLanguage>> {
|
|||
outputs: vec![Some("".to_string()), Some("".to_string())],
|
||||
area_count: 0,
|
||||
user_input: BlockUserInput::None,
|
||||
description: "Forwards the value one block and sends it to multiple destinations".to_string(),
|
||||
description: "Forwards the value one block and sends it to multiple destinations"
|
||||
.to_string(),
|
||||
color: 6,
|
||||
});
|
||||
|
||||
|
@ -113,7 +107,8 @@ pub fn setup_hxdsp_block_language() -> Rc<RefCell<BlockLanguage>> {
|
|||
outputs: vec![Some("".to_string()), Some("".to_string()), Some("".to_string())],
|
||||
area_count: 0,
|
||||
user_input: BlockUserInput::None,
|
||||
description: "Forwards the value one block and sends it to multiple destinations".to_string(),
|
||||
description: "Forwards the value one block and sends it to multiple destinations"
|
||||
.to_string(),
|
||||
color: 6,
|
||||
});
|
||||
|
||||
|
@ -150,57 +145,58 @@ pub fn setup_hxdsp_block_language() -> Rc<RefCell<BlockLanguage>> {
|
|||
area_count: 2,
|
||||
user_input: BlockUserInput::None,
|
||||
description: "Divides the controlflow based on a true (>= 0.5) \
|
||||
or false (< 0.5) input value.".to_string(),
|
||||
or false (< 0.5) input value."
|
||||
.to_string(),
|
||||
color: 0,
|
||||
});
|
||||
|
||||
lang.define(BlockType {
|
||||
category: "nodes".to_string(),
|
||||
name: "1pole".to_string(),
|
||||
rows: 2,
|
||||
inputs: vec![Some("in".to_string()), Some("f".to_string())],
|
||||
outputs: vec![Some("lp".to_string()), Some("hp".to_string())],
|
||||
area_count: 0,
|
||||
user_input: BlockUserInput::None,
|
||||
description: "Runs a simple one pole filter on the input".to_string(),
|
||||
color: 8,
|
||||
});
|
||||
|
||||
lang.define(BlockType {
|
||||
category: "nodes".to_string(),
|
||||
name: "svf".to_string(),
|
||||
rows: 3,
|
||||
inputs: vec![Some("in".to_string()), Some("f".to_string()), Some("r".to_string())],
|
||||
outputs: vec![Some("lp".to_string()), Some("bp".to_string()), Some("hp".to_string())],
|
||||
area_count: 0,
|
||||
user_input: BlockUserInput::None,
|
||||
description: "Runs a state variable filter on the input".to_string(),
|
||||
color: 8,
|
||||
});
|
||||
|
||||
lang.define(BlockType {
|
||||
category: "functions".to_string(),
|
||||
name: "sin".to_string(),
|
||||
rows: 1,
|
||||
inputs: vec![Some("".to_string())],
|
||||
outputs: vec![Some("".to_string())],
|
||||
area_count: 0,
|
||||
user_input: BlockUserInput::None,
|
||||
description: "Calculates the sine of the input".to_string(),
|
||||
color: 16,
|
||||
});
|
||||
|
||||
lang.define(BlockType {
|
||||
category: "nodes".to_string(),
|
||||
name: "delay".to_string(),
|
||||
rows: 2,
|
||||
inputs: vec![Some("in".to_string()), Some("t".to_string())],
|
||||
outputs: vec![Some("".to_string())],
|
||||
area_count: 0,
|
||||
user_input: BlockUserInput::None,
|
||||
description: "Runs a linearly interpolated delay on the input".to_string(),
|
||||
color: 8,
|
||||
});
|
||||
// lang.define(BlockType {
|
||||
// category: "nodes".to_string(),
|
||||
// name: "1pole".to_string(),
|
||||
// rows: 2,
|
||||
// inputs: vec![Some("in".to_string()), Some("f".to_string())],
|
||||
// outputs: vec![Some("lp".to_string()), Some("hp".to_string())],
|
||||
// area_count: 0,
|
||||
// user_input: BlockUserInput::None,
|
||||
// description: "Runs a simple one pole filter on the input".to_string(),
|
||||
// color: 8,
|
||||
// });
|
||||
//
|
||||
// lang.define(BlockType {
|
||||
// category: "nodes".to_string(),
|
||||
// name: "svf".to_string(),
|
||||
// rows: 3,
|
||||
// inputs: vec![Some("in".to_string()), Some("f".to_string()), Some("r".to_string())],
|
||||
// outputs: vec![Some("lp".to_string()), Some("bp".to_string()), Some("hp".to_string())],
|
||||
// area_count: 0,
|
||||
// user_input: BlockUserInput::None,
|
||||
// description: "Runs a state variable filter on the input".to_string(),
|
||||
// color: 8,
|
||||
// });
|
||||
//
|
||||
// lang.define(BlockType {
|
||||
// category: "functions".to_string(),
|
||||
// name: "sin".to_string(),
|
||||
// rows: 1,
|
||||
// inputs: vec![Some("".to_string())],
|
||||
// outputs: vec![Some("".to_string())],
|
||||
// area_count: 0,
|
||||
// user_input: BlockUserInput::None,
|
||||
// description: "Calculates the sine of the input".to_string(),
|
||||
// color: 16,
|
||||
// });
|
||||
//
|
||||
// lang.define(BlockType {
|
||||
// category: "nodes".to_string(),
|
||||
// name: "delay".to_string(),
|
||||
// rows: 2,
|
||||
// inputs: vec![Some("in".to_string()), Some("t".to_string())],
|
||||
// outputs: vec![Some("".to_string())],
|
||||
// area_count: 0,
|
||||
// user_input: BlockUserInput::None,
|
||||
// description: "Runs a linearly interpolated delay on the input".to_string(),
|
||||
// color: 8,
|
||||
// });
|
||||
|
||||
lang.define(BlockType {
|
||||
category: "arithmetics".to_string(),
|
||||
|
@ -219,8 +215,7 @@ pub fn setup_hxdsp_block_language() -> Rc<RefCell<BlockLanguage>> {
|
|||
category: "arithmetics".to_string(),
|
||||
name: fun_name.to_string(),
|
||||
rows: 2,
|
||||
inputs:
|
||||
if fun_name == &"-" || fun_name == &"/" {
|
||||
inputs: if fun_name == &"-" || fun_name == &"/" {
|
||||
vec![Some("a".to_string()), Some("b".to_string())]
|
||||
} else {
|
||||
vec![Some("".to_string()), Some("".to_string())]
|
||||
|
@ -233,6 +228,40 @@ pub fn setup_hxdsp_block_language() -> Rc<RefCell<BlockLanguage>> {
|
|||
});
|
||||
}
|
||||
|
||||
dsp_lib.borrow().for_each(|node_type| -> Result<(), ()> {
|
||||
let max_ports = node_type.input_count().max(node_type.output_count());
|
||||
let is_stateful = node_type.is_stateful();
|
||||
|
||||
let mut inputs = vec![];
|
||||
let mut outputs = vec![];
|
||||
|
||||
let mut i = 0;
|
||||
while let Some(name) = node_type.input_names(i) {
|
||||
inputs.push(Some(name[0..(name.len().min(2))].to_string()));
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
while let Some(name) = node_type.output_names(i) {
|
||||
outputs.push(Some(name[0..(name.len().min(2))].to_string()));
|
||||
i += 1;
|
||||
}
|
||||
|
||||
lang.define(BlockType {
|
||||
category: if is_stateful { "nodes".to_string() } else { "functions".to_string() },
|
||||
name: node_type.name().to_string(),
|
||||
rows: max_ports,
|
||||
area_count: 0,
|
||||
user_input: BlockUserInput::None,
|
||||
description: node_type.documentation().to_string(),
|
||||
color: if is_stateful { 8 } else { 16 },
|
||||
inputs,
|
||||
outputs,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}).expect("seriously no error here");
|
||||
|
||||
lang.define_identifier("in1");
|
||||
lang.define_identifier("in2");
|
||||
lang.define_identifier("israte");
|
||||
|
|
|
@ -281,7 +281,9 @@ impl NodeConfigurator {
|
|||
let mut scopes = vec![];
|
||||
scopes.resize_with(MAX_SCOPES, || ScopeHandle::new_shared());
|
||||
|
||||
let lang = blocklang_def::setup_hxdsp_block_language();
|
||||
let code_engines = vec![CodeEngine::new(); MAX_AVAIL_CODE_ENGINES];
|
||||
|
||||
let lang = blocklang_def::setup_hxdsp_block_language(code_engines[0].get_lib());
|
||||
let mut block_functions = vec![];
|
||||
block_functions.resize_with(MAX_AVAIL_CODE_ENGINES, || {
|
||||
(0, Arc::new(Mutex::new(BlockFun::new(lang.clone()))))
|
||||
|
@ -304,7 +306,7 @@ impl NodeConfigurator {
|
|||
node2idx: HashMap::new(),
|
||||
trackers: vec![Tracker::new(); MAX_AVAIL_TRACKERS],
|
||||
#[cfg(feature = "synfx-dsp-jit")]
|
||||
code_engines: vec![CodeEngine::new(); MAX_AVAIL_CODE_ENGINES],
|
||||
code_engines,
|
||||
block_functions,
|
||||
scopes,
|
||||
},
|
||||
|
|
|
@ -45,6 +45,10 @@ impl CodeEngine {
|
|||
Self { lib, dsp_ctx: DSPNodeContext::new_ref(), update_prod, return_cons }
|
||||
}
|
||||
|
||||
pub fn get_lib(&self) -> Rc<RefCell<DSPNodeTypeLibrary>> {
|
||||
self.lib.clone()
|
||||
}
|
||||
|
||||
pub fn upload(&mut self, ast: Box<ASTNode>) -> Result<(), JITCompileError> {
|
||||
let jit = JIT::new(self.lib.clone(), self.dsp_ctx.clone());
|
||||
let fun = jit.compile(ASTFun::new(ast))?;
|
||||
|
|
|
@ -38,3 +38,4 @@ fn check_node_code_1() {
|
|||
let res = run_for_ms(&mut node_exec, 25.0);
|
||||
assert_decimated_feq!(res.0, 50, vec![0.3; 10]);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue