Wrote bjit to jit translator and got JIT code running in the Code node already
This commit is contained in:
parent
bf79157f8a
commit
c0dad77577
5 changed files with 109 additions and 73 deletions
|
@ -72,13 +72,10 @@ impl ASTNodeRef {
|
|||
}
|
||||
}
|
||||
|
||||
type BlkASTRef = Rc<RefCell<BlkASTNode>>;
|
||||
type BlkASTRef = Rc<BlkASTNode>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum BlkASTNode {
|
||||
Root {
|
||||
child: BlkASTRef,
|
||||
},
|
||||
Area {
|
||||
childs: Vec<BlkASTRef>,
|
||||
},
|
||||
|
@ -88,13 +85,11 @@ enum BlkASTNode {
|
|||
},
|
||||
Get {
|
||||
id: usize,
|
||||
use_count: usize,
|
||||
var: String,
|
||||
},
|
||||
Node {
|
||||
id: usize,
|
||||
out: Option<String>,
|
||||
use_count: usize,
|
||||
typ: String,
|
||||
lbl: String,
|
||||
childs: Vec<(Option<String>, BlkASTRef)>,
|
||||
|
@ -115,60 +110,53 @@ impl BlkASTNode {
|
|||
}
|
||||
|
||||
match self {
|
||||
BlkASTNode::Root { child } => {
|
||||
format!("{}Root\n", indent_str) + &child.borrow().dump(indent + 1, None)
|
||||
}
|
||||
BlkASTNode::Area { childs } => {
|
||||
let mut s = format!("{}Area\n", indent_str);
|
||||
for c in childs.iter() {
|
||||
s += &c.borrow().dump(indent + 1, None);
|
||||
s += &c.dump(indent + 1, None);
|
||||
}
|
||||
s
|
||||
}
|
||||
BlkASTNode::Set { var, expr } => {
|
||||
format!("{}set '{}'=\n", indent_str, var) + &expr.borrow().dump(indent + 1, None)
|
||||
format!("{}set '{}'=\n", indent_str, var) + &expr.dump(indent + 1, None)
|
||||
}
|
||||
BlkASTNode::Get { id, use_count, var } => {
|
||||
format!("{}get '{}' (id={}, use={})\n", indent_str, var, id, use_count)
|
||||
BlkASTNode::Get { id, var } => {
|
||||
format!("{}get '{}' (id={})\n", indent_str, var, id)
|
||||
}
|
||||
BlkASTNode::Literal { value } => {
|
||||
format!("{}{}\n", indent_str, value)
|
||||
}
|
||||
BlkASTNode::Node { id, out, use_count, typ, lbl, childs } => {
|
||||
BlkASTNode::Node { id, out, typ, lbl, childs } => {
|
||||
let lbl = if *typ == *lbl { "".to_string() } else { format!("[{}]", lbl) };
|
||||
|
||||
let mut s = if let Some(out) = out {
|
||||
format!("{}{}{} (id={}/{}, use={})\n", indent_str, typ, lbl, id, out, use_count)
|
||||
format!("{}{}{} (id={}/{})\n", indent_str, typ, lbl, id, out)
|
||||
} else {
|
||||
format!("{}{}{} (id={}, use={})\n", indent_str, typ, lbl, id, use_count)
|
||||
format!("{}{}{} (id={})\n", indent_str, typ, lbl, id)
|
||||
};
|
||||
for (inp, c) in childs.iter() {
|
||||
s += &format!("{}", c.borrow().dump(indent + 1, inp.as_ref().map(|s| &s[..])));
|
||||
s += &format!("{}", c.dump(indent + 1, inp.as_ref().map(|s| &s[..])));
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_root(child: BlkASTRef) -> BlkASTRef {
|
||||
Rc::new(RefCell::new(BlkASTNode::Root { child }))
|
||||
}
|
||||
|
||||
pub fn new_area(childs: Vec<BlkASTRef>) -> BlkASTRef {
|
||||
Rc::new(RefCell::new(BlkASTNode::Area { childs }))
|
||||
Rc::new(BlkASTNode::Area { childs })
|
||||
}
|
||||
|
||||
pub fn new_set(var: &str, expr: BlkASTRef) -> BlkASTRef {
|
||||
Rc::new(RefCell::new(BlkASTNode::Set { var: var.to_string(), expr }))
|
||||
Rc::new(BlkASTNode::Set { var: var.to_string(), expr })
|
||||
}
|
||||
|
||||
pub fn new_get(id: usize, var: &str) -> BlkASTRef {
|
||||
Rc::new(RefCell::new(BlkASTNode::Get { id, var: var.to_string(), use_count: 1 }))
|
||||
Rc::new(BlkASTNode::Get { id, var: var.to_string() })
|
||||
}
|
||||
|
||||
pub fn new_literal(val: &str) -> Result<BlkASTRef, BlkJITCompileError> {
|
||||
if let Ok(value) = val.parse::<f64>() {
|
||||
Ok(Rc::new(RefCell::new(BlkASTNode::Literal { value })))
|
||||
Ok(Rc::new(BlkASTNode::Literal { value }))
|
||||
} else {
|
||||
Err(BlkJITCompileError::BadLiteralNumber(val.to_string()))
|
||||
}
|
||||
|
@ -181,14 +169,13 @@ impl BlkASTNode {
|
|||
lbl: &str,
|
||||
childs: Vec<(Option<String>, BlkASTRef)>,
|
||||
) -> BlkASTRef {
|
||||
Rc::new(RefCell::new(BlkASTNode::Node {
|
||||
Rc::new(BlkASTNode::Node {
|
||||
id,
|
||||
out,
|
||||
typ: typ.to_string(),
|
||||
lbl: lbl.to_string(),
|
||||
use_count: 1,
|
||||
childs,
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,26 +223,6 @@ impl Block2JITCompiler {
|
|||
node: &ASTNodeRef,
|
||||
my_out: Option<String>,
|
||||
) -> Result<BlkASTRef, BlkJITCompileError> {
|
||||
// TODO: Deal with multiple outputs.
|
||||
// If we encounter a node with multiple outputs, assign each output
|
||||
// to a temporary variable and save that.
|
||||
// Store the name of the temporary in a id+output mapping.
|
||||
// => XXX
|
||||
// That means: If we have a single output, things are easy, just plug them into
|
||||
// the JIT ast:
|
||||
// outer(inner())
|
||||
// But if we have multiple outputs:
|
||||
// assign(a = inner())
|
||||
// assign(b = %1)
|
||||
// outer_x(a)
|
||||
// outer_y(b)
|
||||
|
||||
// TODO: Filter out -> nodes from the AST
|
||||
// TODO: For ->2 and ->3, save the input in some variable
|
||||
// and reserve a id+output variable for this.
|
||||
|
||||
// XXX: SSA form of cranelift should take care of the rest!
|
||||
|
||||
let id = node.0.borrow().id;
|
||||
|
||||
if let Some(out) = &my_out {
|
||||
|
@ -394,13 +361,40 @@ impl Block2JITCompiler {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn compile(&mut self, fun: &BlockFun) -> Result<ASTNode, BlkJITCompileError> {
|
||||
pub fn bjit2jit(&mut self, ast: &BlkASTRef) -> Result<Box<ASTNode>, BlkJITCompileError> {
|
||||
use synfx_dsp_jit::build::*;
|
||||
|
||||
match &**ast {
|
||||
BlkASTNode::Area { childs } => {
|
||||
let mut stmt = vec![];
|
||||
for c in childs.iter() {
|
||||
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::Node { id, out, typ, lbl, childs } => {
|
||||
Err(BlkJITCompileError::UnknownError)
|
||||
}
|
||||
BlkASTNode::Literal { value } => {
|
||||
Ok(literal(*value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile(&mut self, fun: &BlockFun) -> Result<Box<ASTNode>, BlkJITCompileError> {
|
||||
let tree = fun.generate_tree::<ASTNodeRef>("zero").unwrap();
|
||||
println!("{}", tree.walk_dump("", "", 0));
|
||||
|
||||
let blkast = self.trans2bjit(&tree, None);
|
||||
println!("R: {}", blkast.unwrap().borrow().dump(0, None));
|
||||
let blkast = self.trans2bjit(&tree, None)?;
|
||||
println!("R: {}", blkast.dump(0, None));
|
||||
|
||||
Err(BlkJITCompileError::UnknownError)
|
||||
self.bjit2jit(&blkast)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ impl DspNode for Code {
|
|||
|
||||
for frame in 0..ctx.nframes() {
|
||||
let (s1, s2, ret) = backend.process(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
||||
println!("OUT: {}", ret);
|
||||
out.write(frame, ret);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::nodes::{NodeConfigurator, NodeGraphOrdering, NodeProg, MAX_ALLOCATED_
|
|||
pub use crate::CellDir;
|
||||
use crate::ScopeHandle;
|
||||
use crate::blocklang::BlockFun;
|
||||
use crate::block_compiler::BlkJITCompileError;
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
|
@ -600,7 +601,7 @@ impl Matrix {
|
|||
/// Checks the block function for the id `id`. If the block function did change,
|
||||
/// updates are then sent to the audio thread.
|
||||
/// See also [get_block_function].
|
||||
pub fn check_block_function(&mut self, id: usize) {
|
||||
pub fn check_block_function(&mut self, id: usize) -> Result<(), BlkJITCompileError> {
|
||||
self.config.check_block_function(id)
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use super::{
|
|||
};
|
||||
use crate::blocklang::*;
|
||||
use crate::blocklang_def;
|
||||
use crate::block_compiler::Block2JITCompiler;
|
||||
use crate::block_compiler::{Block2JITCompiler, BlkJITCompileError};
|
||||
use crate::dsp::tracker::{PatternData, Tracker};
|
||||
use crate::dsp::{node_factory, Node, NodeId, NodeInfo, ParamId, SAtom};
|
||||
use crate::monitor::{new_monitor_processor, MinMaxMonitorSamples, Monitor, MON_SIG_CNT};
|
||||
|
@ -695,33 +695,36 @@ impl NodeConfigurator {
|
|||
/// Checks the block function for the id `id`. If the block function did change,
|
||||
/// updates are then sent to the audio thread.
|
||||
/// See also [get_block_function].
|
||||
pub fn check_block_function(&mut self, id: usize) {
|
||||
pub fn check_block_function(&mut self, id: usize) -> Result<(), BlkJITCompileError> {
|
||||
if let Some((generation, block_fun)) = self.block_functions.get_mut(id) {
|
||||
if let Ok(block_fun) = block_fun.lock() {
|
||||
if *generation != block_fun.generation() {
|
||||
*generation = block_fun.generation();
|
||||
let mut compiler = Block2JITCompiler::new(block_fun.block_language());
|
||||
compiler.compile(&block_fun);
|
||||
let ast = compiler.compile(&block_fun)?;
|
||||
|
||||
// let ast = block_compiler::compile(block_fun);
|
||||
if let Some(cod) = self.code_engines.get_mut(id) {
|
||||
use synfx_dsp_jit::build::*;
|
||||
cod.upload(stmts(&[
|
||||
assign(
|
||||
"*phase",
|
||||
op_add(var("*phase"), op_mul(literal(440.0), var("israte"))),
|
||||
),
|
||||
_if(
|
||||
op_gt(var("*phase"), literal(1.0)),
|
||||
assign("*phase", op_sub(var("*phase"), literal(1.0))),
|
||||
None,
|
||||
),
|
||||
var("*phase"),
|
||||
]));
|
||||
cod.upload(ast);
|
||||
// stmts(&[
|
||||
// assign(
|
||||
// "*phase",
|
||||
// op_add(var("*phase"), op_mul(literal(440.0), var("israte"))),
|
||||
// ),
|
||||
// _if(
|
||||
// op_gt(var("*phase"), literal(1.0)),
|
||||
// assign("*phase", op_sub(var("*phase"), literal(1.0))),
|
||||
// None,
|
||||
// ),
|
||||
// var("*phase"),
|
||||
// ]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Retrieve a handle to the block function `id`. In case you modify the block function,
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
mod common;
|
||||
use common::*;
|
||||
|
||||
#[test]
|
||||
fn check_blocklang_1() {
|
||||
let (node_conf, mut node_exec) = new_node_engine();
|
||||
fn setup() -> (Matrix, NodeExecutor) {
|
||||
let (node_conf, node_exec) = new_node_engine();
|
||||
let mut matrix = Matrix::new(node_conf, 3, 3);
|
||||
|
||||
let mut chain = MatrixCellChain::new(CellDir::B);
|
||||
|
@ -20,7 +19,45 @@ fn check_blocklang_1() {
|
|||
.unwrap();
|
||||
matrix.sync().unwrap();
|
||||
|
||||
let code = NodeId::Code(0);
|
||||
(matrix, node_exec)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_blocklang_1() {
|
||||
let (mut matrix, mut node_exec) = setup();
|
||||
|
||||
let block_fun = matrix.get_block_function(0).expect("block fun exists");
|
||||
{
|
||||
let mut block_fun = block_fun.lock().expect("matrix lock");
|
||||
block_fun.instanciate_at(0, 0, 1, "value", Some("0.3".to_string()));
|
||||
// block_fun.instanciate_at(0, 1, 1, "set", Some("&sig1".to_string()));
|
||||
}
|
||||
|
||||
matrix.check_block_function(0).expect("no compile error");
|
||||
|
||||
let res = run_for_ms(&mut node_exec, 25.0);
|
||||
println!("RES: {:?}", res.1);
|
||||
assert_decimated_feq!(
|
||||
res.0,
|
||||
50,
|
||||
vec![
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
]
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn check_blocklang_2() {
|
||||
let (mut matrix, mut node_exec) = setup();
|
||||
|
||||
let block_fun = matrix.get_block_function(0).expect("block fun exists");
|
||||
{
|
||||
|
@ -55,7 +92,7 @@ fn check_blocklang_1() {
|
|||
block_fun.instanciate_at(0, 4, 4, "set", Some("*ap".to_string()));
|
||||
}
|
||||
|
||||
matrix.check_block_function(0);
|
||||
matrix.check_block_function(0).expect("no compile error");
|
||||
|
||||
let res = run_for_ms(&mut node_exec, 25.0);
|
||||
assert_decimated_feq!(
|
||||
|
|
Loading…
Reference in a new issue