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::<i32>(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::<bool>(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::<i32>(0);
let y = builder.new_param::<i32>(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::<f32>(0);
let y = builder.new_param::<f32>(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::<i32>(0);
let zero = builder.new_constant::<i32>(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::<i32>(0);
let zero = builder.new_constant::<i32>(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::<bool>(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::<i32>(0);
let zero = builder.new_constant::<i32>(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::<bool>(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::<i32>(0);
let zero = builder.new_constant::<i32>(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::<bool>(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::<i32>(0);
let n = builder.new_variable(param.cast());
let one = builder.new_constant::<i32>(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::<i32>(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::<i32>(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::<i32>(n.get().cast(), one).cast(),
);
});
builder.bind(end_block);
builder.new_return(Some(z.get()));
builder.finalize()
});
compiler.finalize::<Isa>();
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::<i32>(0);
let one = builder.new_constant::<i32>(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::<i32>(0);
let x = builder.new_call::<i32>(Symbol::named("add_one"), &[param.cast()]);
let one = builder.new_constant::<i32>(1);
let ret = builder.new_add(one, x);
builder.new_return(Some(ret));
builder.finalize()
});
compiler.finalize::<Isa>();
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::<i32>(0);
let one = builder.new_constant::<i32>(1);
let _ret = builder.new_add(param, one); let ret = builder.new_add(param, one);
builder.new_return(Some(ret));
builder.finalize()
});
compiler.finalize::<Isa>();
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::<i32>(0);
let one = builder.new_constant::<i32>(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::<i32>(0);
let _x = builder.new_call::<i32>(Symbol::named("add_one"), &[param.cast()]); let x = builder.new_call::<i32>(Symbol::named("add_one"), &[param.cast()]);
let _x = builder.new_call::<i32>(Symbol::named("add_one"), &[param.cast()]); let one = builder.new_constant::<i32>(1);
let ret = builder.new_add(one, x);
builder.new_return(Some(ret));
builder.finalize()
});
compiler.finalize::<Isa>();
let code = compiler.get(&Symbol::named("add_two"));
assert_eq!(code.invoke(&[Value::I32(233)]), Some(Value::I32(235)));
}