Wrote bjit to jit translator and got JIT code running in the Code node already

This commit is contained in:
Weird Constructor 2022-08-01 03:56:38 +02:00
parent bf79157f8a
commit c0dad77577
5 changed files with 109 additions and 73 deletions

View file

@ -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)
} }
} }

View file

@ -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);
} }

View file

@ -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)
} }

View file

@ -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,

View file

@ -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!(