use alduin::compiler::compiled_code::Symbol; use alduin::compiler::graph::{BaseGraphBuilder, Graph, Signature, Type}; use alduin::compiler::Compiler; use alduin::rt::Value; type Isa = alduin::backend::x64::X64; #[test] fn empty() { let compiler = Compiler::new(); compiler.compile(Symbol::named("test"), { let graph = Graph::new(Signature(vec![], Type::Void)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); builder.new_return::<()>(None); builder.finalize() }); let code = compiler.get(&Symbol::named("test")); assert_eq!(code.invoke(&[]), None); } #[test] fn return_constant() { let compiler = Compiler::new(); compiler.compile(Symbol::named("test"), { let graph = Graph::new(Signature(vec![], Type::I32)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let zero = builder.new_constant(233i32); builder.new_return(Some(zero)); builder.finalize() }); let code = compiler.get(&Symbol::named("test")); assert_eq!(code.invoke(&[]), Some(Value::I32(233))); } #[test] fn return_param() { let compiler = Compiler::new(); compiler.compile(Symbol::named("test"), { let graph = Graph::new(Signature(vec![Type::I32], Type::I32)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let param = builder.new_param::(0); builder.new_return(Some(param)); builder.finalize() }); let code = compiler.get(&Symbol::named("test")); assert_eq!(code.invoke(&[Value::I32(233)]), Some(Value::I32(233))); } #[test] fn boolean_negate() { let compiler = Compiler::new(); compiler.compile(Symbol::named("test"), { let graph = Graph::new(Signature(vec![Type::Bool], Type::Bool)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let param = builder.new_param::(0); let negation = builder.new_not(param); builder.new_return(Some(negation)); builder.finalize() }); let code = compiler.get(&Symbol::named("test")); assert_eq!(code.invoke(&[Value::Bool(true)]), Some(Value::Bool(false))); assert_eq!(code.invoke(&[Value::Bool(false)]), Some(Value::Bool(true))); } #[test] fn i32_add() { let compiler = Compiler::new(); compiler.compile(Symbol::named("test"), { let graph = Graph::new(Signature(vec![Type::I32, Type::I32], Type::I32)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let x = builder.new_param::(0); let y = builder.new_param::(1); let z = builder.new_add(x, y); builder.new_return(Some(z)); builder.finalize() }); let code = compiler.get(&Symbol::named("test")); assert_eq!( code.invoke(&[Value::I32(200), Value::I32(33)]), Some(Value::I32(233)) ); } #[test] fn f32_add() { let compiler = Compiler::new(); compiler.compile(Symbol::named("test"), { let graph = Graph::new(Signature(vec![Type::F32, Type::F32], Type::F32)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let x = builder.new_param::(0); let y = builder.new_param::(1); let z = builder.new_add(x, y); builder.new_return(Some(z)); builder.finalize() }); let code = compiler.get(&Symbol::named("test")); assert_eq!( code.invoke(&[Value::F32(200f32), Value::F32(33f32)]), Some(Value::F32(233f32)) ); } #[test] fn i32_is_positive_0() { let compiler = Compiler::new(); compiler.compile(Symbol::named("test"), { let graph = Graph::new(Signature(vec![Type::I32], Type::Bool)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let x = builder.new_param::(0); let zero = builder.new_constant::(0); let y = builder.new_gt_s(x, zero); builder.new_return(Some(y)); builder.finalize() }); let code = compiler.get(&Symbol::named("test")); assert_eq!(code.invoke(&[Value::I32(1)]), Some(Value::Bool(true))); assert_eq!(code.invoke(&[Value::I32(0)]), Some(Value::Bool(false))); assert_eq!(code.invoke(&[Value::I32(-1)]), Some(Value::Bool(false))); } #[test] fn i32_is_positive_1() { let compiler = Compiler::new(); compiler.compile(Symbol::named("test"), { let graph = Graph::new(Signature(vec![Type::I32], Type::Bool)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let x = builder.new_param::(0); let zero = builder.new_constant::(0); let y = builder.new_gt_s(x, zero); let v = builder.new_constant(false); let r = builder.new_variable(v.cast()); builder .r#if(y) .then_(|builder| { let v = builder.new_constant(true); r.set(builder.control(), v.cast()); }) .else_(|builder| { let v = builder.new_constant(false); r.set(builder.control(), v.cast()); }) .finish(); builder.new_return::(Some(r.get().cast())); builder.finalize() }); let code = compiler.get(&Symbol::named("test")); assert_eq!(code.invoke(&[Value::I32(1)]), Some(Value::Bool(true))); assert_eq!(code.invoke(&[Value::I32(0)]), Some(Value::Bool(false))); assert_eq!(code.invoke(&[Value::I32(-1)]), Some(Value::Bool(false))); } #[test] fn i32_is_positive_2() { let compiler = Compiler::new(); compiler.compile(Symbol::named("test"), { let graph = Graph::new(Signature(vec![Type::I32], Type::Bool)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let x = builder.new_param::(0); let zero = builder.new_constant::(0); let y = builder.new_gt_s(x, zero); let v = builder.new_constant(false); let r = builder.new_variable(v.cast()); builder .r#if(y) .then_(|builder| { let v = builder.new_constant(true); r.set(builder.control(), v.cast()); }) .finish(); builder.new_return::(Some(r.get().cast())); builder.finalize() }); let code = compiler.get(&Symbol::named("test")); assert_eq!(code.invoke(&[Value::I32(1)]), Some(Value::Bool(true))); assert_eq!(code.invoke(&[Value::I32(0)]), Some(Value::Bool(false))); assert_eq!(code.invoke(&[Value::I32(-1)]), Some(Value::Bool(false))); } #[test] fn i32_is_positive_3() { let compiler = Compiler::new(); compiler.compile(Symbol::named("test"), { let graph = Graph::new(Signature(vec![Type::I32], Type::Bool)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let x = builder.new_param::(0); let zero = builder.new_constant::(0); let y = builder.new_gt_s(x, zero); let v = builder.new_constant(false); let r = builder.new_variable(v.cast()); builder .r#if(y) .then_(|builder| { let v = builder.new_constant(true); r.set(builder.control(), v.cast()); }) .else_(|_| {}) .finish(); builder.new_return::(Some(r.get().cast())); builder.finalize() }); let code = compiler.get(&Symbol::named("test")); assert_eq!(code.invoke(&[Value::I32(1)]), Some(Value::Bool(true))); assert_eq!(code.invoke(&[Value::I32(0)]), Some(Value::Bool(false))); assert_eq!(code.invoke(&[Value::I32(-1)]), Some(Value::Bool(false))); } #[test] fn fibonacci() { let mut compiler = Compiler::new(); compiler.compile(Symbol::named("test"), { let graph = Graph::new(Signature(vec![Type::I32], Type::I32)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let param = builder.new_param::(0); let n = builder.new_variable(param.cast()); let one = builder.new_constant::(1); let x = builder.new_variable(one.cast()); let y = builder.new_variable(one.cast()); let z = builder.new_variable(one.cast()); let end_block = builder.new_region(&[]); builder.r#loop().body(|builder| { let cond = builder.new_le_s::(n.get().cast(), one); let loop_body = builder.new_region(&[]); builder.new_branch(cond, end_block, loop_body); builder.bind(loop_body); z.set( builder.control(), builder .new_add::(x.get().cast(), y.get().cast()) .cast(), ); x.set(builder.control(), y.get()); y.set(builder.control(), z.get()); n.set( builder.control(), builder.new_sub::(n.get().cast(), one).cast(), ); }); builder.bind(end_block); builder.new_return(Some(z.get())); builder.finalize() }); compiler.finalize::(); let code = compiler.get(&Symbol::named("test")); fn fib(n: i32) -> i32 { if n <= 1 { 1 } else { fib(n - 1) + fib(n - 2) } } for i in 0..10 { assert_eq!(code.invoke(&[Value::I32(i)]), Some(Value::I32(fib(i)))); } } #[test] fn func_call() { let mut compiler = Compiler::new(); compiler.compile(Symbol::named("add_one"), { let graph = Graph::new(Signature(vec![Type::I32], Type::I32)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let param = builder.new_param::(0); let one = builder.new_constant::(1); let ret = builder.new_add(param, one); builder.new_return(Some(ret)); builder.finalize() }); compiler.compile(Symbol::named("add_two"), { let graph = Graph::new(Signature(vec![Type::I32], Type::I32)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let param = builder.new_param::(0); let x = builder.new_call::(Symbol::named("add_one"), &[param.cast()]); let one = builder.new_constant::(1); let ret = builder.new_add(one, x); builder.new_return(Some(ret)); builder.finalize() }); compiler.finalize::(); let code = compiler.get(&Symbol::named("add_two")); assert_eq!(code.invoke(&[Value::I32(233)]), Some(Value::I32(235))); } #[test] fn unused_value() { let mut compiler = Compiler::new(); compiler.compile(Symbol::named("add_one"), { let graph = Graph::new(Signature(vec![Type::I32], Type::I32)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let param = builder.new_param::(0); let one = builder.new_constant::(1); let _ret = builder.new_add(param, one); // Unused instruction let ret = builder.new_add(param, one); builder.new_return(Some(ret)); builder.finalize() }); compiler.finalize::(); let code = compiler.get(&Symbol::named("add_one")); assert_eq!(code.invoke(&[Value::I32(233)]), Some(Value::I32(234))); } #[test] fn unused_func_call() { let mut compiler = Compiler::new(); compiler.compile(Symbol::named("add_one"), { let graph = Graph::new(Signature(vec![Type::I32], Type::I32)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let param = builder.new_param::(0); let one = builder.new_constant::(1); let ret = builder.new_add(param, one); builder.new_return(Some(ret)); builder.finalize() }); compiler.compile(Symbol::named("add_two"), { let graph = Graph::new(Signature(vec![Type::I32], Type::I32)); let mut builder = BaseGraphBuilder::new(graph); let start = builder.new_start(); builder.bind(start); let param = builder.new_param::(0); let _x = builder.new_call::(Symbol::named("add_one"), &[param.cast()]); // redundant call let x = builder.new_call::(Symbol::named("add_one"), &[param.cast()]); let _x = builder.new_call::(Symbol::named("add_one"), &[param.cast()]); // redundant call let one = builder.new_constant::(1); let ret = builder.new_add(one, x); builder.new_return(Some(ret)); builder.finalize() }); compiler.finalize::(); let code = compiler.get(&Symbol::named("add_two")); assert_eq!(code.invoke(&[Value::I32(233)]), Some(Value::I32(235))); }