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)]
|
#[derive(Debug, Clone)]
|
||||||
enum BlkASTNode {
|
enum BlkASTNode {
|
||||||
Root {
|
|
||||||
child: BlkASTRef,
|
|
||||||
},
|
|
||||||
Area {
|
Area {
|
||||||
childs: Vec<BlkASTRef>,
|
childs: Vec<BlkASTRef>,
|
||||||
},
|
},
|
||||||
|
@ -88,13 +85,11 @@ enum BlkASTNode {
|
||||||
},
|
},
|
||||||
Get {
|
Get {
|
||||||
id: usize,
|
id: usize,
|
||||||
use_count: usize,
|
|
||||||
var: String,
|
var: String,
|
||||||
},
|
},
|
||||||
Node {
|
Node {
|
||||||
id: usize,
|
id: usize,
|
||||||
out: Option<String>,
|
out: Option<String>,
|
||||||
use_count: usize,
|
|
||||||
typ: String,
|
typ: String,
|
||||||
lbl: String,
|
lbl: String,
|
||||||
childs: Vec<(Option<String>, BlkASTRef)>,
|
childs: Vec<(Option<String>, BlkASTRef)>,
|
||||||
|
@ -115,60 +110,53 @@ impl BlkASTNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
BlkASTNode::Root { child } => {
|
|
||||||
format!("{}Root\n", indent_str) + &child.borrow().dump(indent + 1, None)
|
|
||||||
}
|
|
||||||
BlkASTNode::Area { childs } => {
|
BlkASTNode::Area { childs } => {
|
||||||
let mut s = format!("{}Area\n", indent_str);
|
let mut s = format!("{}Area\n", indent_str);
|
||||||
for c in childs.iter() {
|
for c in childs.iter() {
|
||||||
s += &c.borrow().dump(indent + 1, None);
|
s += &c.dump(indent + 1, None);
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
BlkASTNode::Set { var, expr } => {
|
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 } => {
|
BlkASTNode::Get { id, var } => {
|
||||||
format!("{}get '{}' (id={}, use={})\n", indent_str, var, id, use_count)
|
format!("{}get '{}' (id={})\n", indent_str, var, id)
|
||||||
}
|
}
|
||||||
BlkASTNode::Literal { value } => {
|
BlkASTNode::Literal { value } => {
|
||||||
format!("{}{}\n", indent_str, 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 lbl = if *typ == *lbl { "".to_string() } else { format!("[{}]", lbl) };
|
||||||
|
|
||||||
let mut s = if let Some(out) = out {
|
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 {
|
} 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() {
|
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
|
s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_root(child: BlkASTRef) -> BlkASTRef {
|
|
||||||
Rc::new(RefCell::new(BlkASTNode::Root { child }))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_area(childs: Vec<BlkASTRef>) -> BlkASTRef {
|
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 {
|
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 {
|
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> {
|
pub fn new_literal(val: &str) -> Result<BlkASTRef, BlkJITCompileError> {
|
||||||
if let Ok(value) = val.parse::<f64>() {
|
if let Ok(value) = val.parse::<f64>() {
|
||||||
Ok(Rc::new(RefCell::new(BlkASTNode::Literal { value })))
|
Ok(Rc::new(BlkASTNode::Literal { value }))
|
||||||
} else {
|
} else {
|
||||||
Err(BlkJITCompileError::BadLiteralNumber(val.to_string()))
|
Err(BlkJITCompileError::BadLiteralNumber(val.to_string()))
|
||||||
}
|
}
|
||||||
|
@ -181,14 +169,13 @@ impl BlkASTNode {
|
||||||
lbl: &str,
|
lbl: &str,
|
||||||
childs: Vec<(Option<String>, BlkASTRef)>,
|
childs: Vec<(Option<String>, BlkASTRef)>,
|
||||||
) -> BlkASTRef {
|
) -> BlkASTRef {
|
||||||
Rc::new(RefCell::new(BlkASTNode::Node {
|
Rc::new(BlkASTNode::Node {
|
||||||
id,
|
id,
|
||||||
out,
|
out,
|
||||||
typ: typ.to_string(),
|
typ: typ.to_string(),
|
||||||
lbl: lbl.to_string(),
|
lbl: lbl.to_string(),
|
||||||
use_count: 1,
|
|
||||||
childs,
|
childs,
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,26 +223,6 @@ impl Block2JITCompiler {
|
||||||
node: &ASTNodeRef,
|
node: &ASTNodeRef,
|
||||||
my_out: Option<String>,
|
my_out: Option<String>,
|
||||||
) -> Result<BlkASTRef, BlkJITCompileError> {
|
) -> 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;
|
let id = node.0.borrow().id;
|
||||||
|
|
||||||
if let Some(out) = &my_out {
|
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();
|
let tree = fun.generate_tree::<ASTNodeRef>("zero").unwrap();
|
||||||
println!("{}", tree.walk_dump("", "", 0));
|
println!("{}", tree.walk_dump("", "", 0));
|
||||||
|
|
||||||
let blkast = self.trans2bjit(&tree, None);
|
let blkast = self.trans2bjit(&tree, None)?;
|
||||||
println!("R: {}", blkast.unwrap().borrow().dump(0, 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() {
|
for frame in 0..ctx.nframes() {
|
||||||
let (s1, s2, ret) = backend.process(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
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);
|
out.write(frame, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::nodes::{NodeConfigurator, NodeGraphOrdering, NodeProg, MAX_ALLOCATED_
|
||||||
pub use crate::CellDir;
|
pub use crate::CellDir;
|
||||||
use crate::ScopeHandle;
|
use crate::ScopeHandle;
|
||||||
use crate::blocklang::BlockFun;
|
use crate::blocklang::BlockFun;
|
||||||
|
use crate::block_compiler::BlkJITCompileError;
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
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,
|
/// Checks the block function for the id `id`. If the block function did change,
|
||||||
/// updates are then sent to the audio thread.
|
/// updates are then sent to the audio thread.
|
||||||
/// See also [get_block_function].
|
/// 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)
|
self.config.check_block_function(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use super::{
|
||||||
};
|
};
|
||||||
use crate::blocklang::*;
|
use crate::blocklang::*;
|
||||||
use crate::blocklang_def;
|
use crate::blocklang_def;
|
||||||
use crate::block_compiler::Block2JITCompiler;
|
use crate::block_compiler::{Block2JITCompiler, BlkJITCompileError};
|
||||||
use crate::dsp::tracker::{PatternData, Tracker};
|
use crate::dsp::tracker::{PatternData, Tracker};
|
||||||
use crate::dsp::{node_factory, Node, NodeId, NodeInfo, ParamId, SAtom};
|
use crate::dsp::{node_factory, Node, NodeId, NodeInfo, ParamId, SAtom};
|
||||||
use crate::monitor::{new_monitor_processor, MinMaxMonitorSamples, Monitor, MON_SIG_CNT};
|
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,
|
/// Checks the block function for the id `id`. If the block function did change,
|
||||||
/// updates are then sent to the audio thread.
|
/// updates are then sent to the audio thread.
|
||||||
/// See also [get_block_function].
|
/// 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 Some((generation, block_fun)) = self.block_functions.get_mut(id) {
|
||||||
if let Ok(block_fun) = block_fun.lock() {
|
if let Ok(block_fun) = block_fun.lock() {
|
||||||
if *generation != block_fun.generation() {
|
if *generation != block_fun.generation() {
|
||||||
*generation = block_fun.generation();
|
*generation = block_fun.generation();
|
||||||
let mut compiler = Block2JITCompiler::new(block_fun.block_language());
|
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);
|
// let ast = block_compiler::compile(block_fun);
|
||||||
if let Some(cod) = self.code_engines.get_mut(id) {
|
if let Some(cod) = self.code_engines.get_mut(id) {
|
||||||
use synfx_dsp_jit::build::*;
|
use synfx_dsp_jit::build::*;
|
||||||
cod.upload(stmts(&[
|
cod.upload(ast);
|
||||||
assign(
|
// stmts(&[
|
||||||
"*phase",
|
// assign(
|
||||||
op_add(var("*phase"), op_mul(literal(440.0), var("israte"))),
|
// "*phase",
|
||||||
),
|
// op_add(var("*phase"), op_mul(literal(440.0), var("israte"))),
|
||||||
_if(
|
// ),
|
||||||
op_gt(var("*phase"), literal(1.0)),
|
// _if(
|
||||||
assign("*phase", op_sub(var("*phase"), literal(1.0))),
|
// op_gt(var("*phase"), literal(1.0)),
|
||||||
None,
|
// assign("*phase", op_sub(var("*phase"), literal(1.0))),
|
||||||
),
|
// None,
|
||||||
var("*phase"),
|
// ),
|
||||||
]));
|
// var("*phase"),
|
||||||
|
// ]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve a handle to the block function `id`. In case you modify the block function,
|
/// Retrieve a handle to the block function `id`. In case you modify the block function,
|
||||||
|
|
|
@ -5,9 +5,8 @@
|
||||||
mod common;
|
mod common;
|
||||||
use common::*;
|
use common::*;
|
||||||
|
|
||||||
#[test]
|
fn setup() -> (Matrix, NodeExecutor) {
|
||||||
fn check_blocklang_1() {
|
let (node_conf, node_exec) = new_node_engine();
|
||||||
let (node_conf, mut node_exec) = new_node_engine();
|
|
||||||
let mut matrix = Matrix::new(node_conf, 3, 3);
|
let mut matrix = Matrix::new(node_conf, 3, 3);
|
||||||
|
|
||||||
let mut chain = MatrixCellChain::new(CellDir::B);
|
let mut chain = MatrixCellChain::new(CellDir::B);
|
||||||
|
@ -20,7 +19,45 @@ fn check_blocklang_1() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
matrix.sync().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");
|
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()));
|
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);
|
let res = run_for_ms(&mut node_exec, 25.0);
|
||||||
assert_decimated_feq!(
|
assert_decimated_feq!(
|
||||||
|
|
Loading…
Reference in a new issue