Test framework now supports tests like test_convop which produce an additional source file

Working test groups: binop, floating_point, alloc, convop, controlflow
parent 2852ac05
......@@ -40,6 +40,7 @@ use compiler::frame::Frame;
use utils::math;
use utils::POINTER_SIZE;
use utils::BitSize;
use std::collections::HashMap;
use std::any::Any;
......@@ -787,7 +788,20 @@ impl <'a> InstructionSelection {
(_, 16) => {
let (res_l, res_h) = self.split_int128(&tmp_res, f_context, vm);
self.backend.emit_mov_r_r(&res_l, unsafe {&tmp_op.as_type(UINT64_TYPE.clone())});
// self.backend.emit_mov_r_r(&res_l, unsafe {&tmp_op.as_type(UINT64_TYPE.clone())});
// use the temp as 64bit temp, mask it
let tmp_op64 =
unsafe { &tmp_op.as_type(UINT64_TYPE.clone()) };
self.emit_apply_mask(
&tmp_op64,
from_ty_size * 8,
f_context,
vm
);
// use temp as lower bits
// clear higher bits
self.backend.emit_mov_r_r(&res_l, &tmp_op64);
self.backend.emit_mov_r_imm(&res_h, 0);
}
// else
......@@ -834,7 +848,8 @@ impl <'a> InstructionSelection {
// mov res_l -> res_h
// sar res_h 63
self.backend.emit_mov_r_r(&res_h, unsafe {&res_l.as_type(UINT32_TYPE.clone())});
// self.backend.emit_mov_r_r(&res_h, unsafe {&res_l.as_type(UINT32_TYPE.clone())});
self.backend.emit_mov_r_r(&res_h, &res_l);
self.backend.emit_sar_r_imm8(&res_h, 63i8);
}
_ => self.backend.emit_movs_r_r(&tmp_res, &tmp_op)
......@@ -921,6 +936,14 @@ impl <'a> InstructionSelection {
}
2 | 1 => {
let tmp_op32 = unsafe { tmp_op.as_type(UINT32_TYPE.clone()) };
// apply mask, otherwise higher bits are arbitrary
self.emit_apply_mask(
&tmp_op32,
op_ty_size * 8,
f_context,
vm
);
self.backend.emit_cvtsi2sd_f64_r(&tmp_res, &tmp_op32);
}
_ => panic!("not implemented int length {}", op_ty_size)
......@@ -984,7 +1007,16 @@ impl <'a> InstructionSelection {
}
2 | 1 => {
let tmp_op32 = unsafe {tmp_op.as_type(UINT32_TYPE.clone())};
// apply mask, otherwise higher bits are arbitrary
self.emit_apply_mask(
&tmp_op32,
op_ty_size * 8,
f_context,
vm
);
// cvtsi2ss %tmp_op32 -> %tmp_res
self.backend.emit_cvtsi2ss_f32_r(&tmp_res, &tmp_op32);
}
......@@ -4807,7 +4839,45 @@ impl <'a> InstructionSelection {
(arg_l, arg_h)
}
}
/// apply mask on an integer register
fn emit_apply_mask(
&mut self,
reg: &P<Value>,
length: BitSize,
f_context: &mut FunctionContext,
vm: &VM
) {
if length <= 32 {
let mask = if length == 32 {
use std::u32;
u32::MAX as i32
} else {
((1u32 << length) - 1) as i32
};
self.backend.emit_and_r_imm(reg, mask);
} else if length <= 64 {
// the mask cannot be an immediate, we need to put it to a temp
let mask = if length == 64 {
use std::u64;
u64::MAX as i64
} else {
((1u64 << length) - 1) as i64
};
let tmp_mask = self.make_temporary(f_context, UINT64_TYPE.clone(), vm);
self.backend.emit_mov_r64_imm64(&tmp_mask, mask);
// apply mask
self.backend.emit_and_r_r(reg, &tmp_mask);
} else {
panic!(
"expect masking an integer register with length <= 64, found {}",
length
);
}
}
fn finish_block(&mut self) {
let cur_block = self.current_block.as_ref().unwrap().clone();
self.backend.end_block(cur_block.clone());
......
......@@ -528,5 +528,254 @@ pub fn run_test(vm: &VM, test_name: &str, tester_name: &str){
assert!(output.status.success());
assert!(test_succeeded == 1);
}
#[cfg(not(feature = "sel4-rumprun"))]
pub fn run_test_2f(vm: &VM, test_name: &str, dep_name: &str, tester_name: &str){
let output_name = test_name.to_string()+ "_" + tester_name;
let executable = link_test_primordial(vec![test_name.to_string(), dep_name.to_string(), tester_name.to_string()], output_name.as_str(), vm);
execute(executable);
}
#[cfg(feature = "sel4-rumprun")]
pub fn run_test_2f(vm: &VM, test_name: &str, dep_name: &str, tester_name: &str){
use std::fs::File;
// emit/add.s
let test_asm_file = "emit/".to_string() + test_name + ".s";
// emit/add_test1.s
let tester_asm_file = "emit/".to_string() + tester_name + ".s";
// emit/context.s
let context_asm_file = "emit/".to_string() + "context.s";
// emit/mu_sym_table.s
let mu_sym_table_asm_file = "emit/".to_string() + "mu_sym_table.s";
// something like emit/dummy_call.s
let dep_asm_file = "emit/".to_string() + dep_name + ".s";
// clean the destination first
let destination_prefix = "../rumprun-sel4/apps/zebu_rt/src/emit/";
let output = Command::new("rm")
.arg("-R")
.arg(destination_prefix)
.output()
.expect("failed to RM dest emit");
assert!(output.status.success());
// recreate the emit folder, deleted by the previous command
let output = Command::new("mkdir")
.arg(destination_prefix)
.output()
.expect("failed to RM dest emit");
assert!(output.status.success());
// above file will be pasted in \
// rumprun-sel4/apps/zebu_rt/src + the above Strings
let destination_prefix = "../rumprun-sel4/apps/zebu_rt/src/";
let dest_test_asm_file = destination_prefix.to_string() + &test_asm_file;
let dest_tester_asm_file = destination_prefix.to_string() + &tester_asm_file;
let dest_context_asm_file = destination_prefix.to_string() + &context_asm_file;
let dest_mu_sym_table_asm_file = destination_prefix.to_string() + &mu_sym_table_asm_file;
let dest_dep_asm_file = destination_prefix.to_string() + &dep_asm_file;
/*
The following 4 commands, copy 4 asm source files to \
the proper location of filesystem for sel4-rumprun runtime
This is currently src/emit
*/
let output = Command::new("cp")
.arg(&test_asm_file)
.arg(&dest_test_asm_file)
.output()
.expect("failed to copy test_asm_file");
assert!(output.status.success());
let output = Command::new("cp")
.arg(&tester_asm_file)
.arg(&dest_tester_asm_file)
.output()
.expect("failed to copy tester_asm_file");
assert!(output.status.success());
let output = Command::new("cp")
.arg(&context_asm_file)
.arg(&dest_context_asm_file)
.output()
.expect("failed to copy context_asm_file");
assert!(output.status.success());
let output = Command::new("cp")
.arg(&mu_sym_table_asm_file)
.arg(&dest_mu_sym_table_asm_file)
.output()
.expect("failed to copy dest_mu_sym_table_asm_file");
assert!(output.status.success());
let output = Command::new("cp")
.arg(&dep_asm_file)
.arg(&dest_dep_asm_file)
.output()
.expect("failed to copy dep_asm_file");
assert!(output.status.success());
/*
Everything is ready for our sel4-rumprun Zebu runtime
to start building the final test executable(s)
*/
use std::os::unix::io::FromRawFd;
use std::os::unix::io::AsRawFd;
let output = Command::new("rm")
.arg("outputs.txt")
.output()
.expect("failed to change directory2");
let mut outputs_file = File::create("outputs.txt").unwrap();
let rawfd = outputs_file.as_raw_fd();
let rawfd = unsafe { File::from_raw_fd(rawfd) };
let output = Command::new("bash")
.arg("build_for_sel4_rumprun.sh")
.stdout(Stdio::inherit())
.output()
.expect("failed to Build");
println!("****************************************");
println!("Build Output -{:?}-", output);
println!("****************************************");
assert!(output.status.success());
// First create a child process which runs qemu for testing
// Then, create a watchdog to check if test is finished
let mut tester_proc = Command::new("qemu-system-x86_64")
.arg("-nographic")
.arg("-m")
.arg("512")
.arg("-kernel")
.arg("../rumprun-sel4/images/kernel-x86_64-pc99")
.arg("-initrd")
.arg("../rumprun-sel4/images/roottask-image-x86_64-pc99")
.arg("-cpu")
.arg("Haswell")
.stdout(rawfd)
.spawn()
.expect("failed to RUN");
use std::thread;
use std::io;
use std::io::prelude::*;
let mut child_proc_finished = 0;
let mut test_succeeded = 0;
let mut test_length = 0;
let test_length_max = 60; // Maximum allowed length for a test is currently 60 seconds
// This loop checks the output file to recognize when qemu vm \
// which is running the test, should be terminated
while child_proc_finished == 0 {
thread::sleep_ms(5000);
test_length += 5;
{
let mut results_file = File::open("outputs.txt");
let mut results_file = match results_file {
Ok(the_file) => the_file,
Err(error) => { panic!("Checking outputs file failed with error -{}-", error); }
};
let mut file_content = String::new();
results_file.read_to_string(&mut file_content);
if file_content.contains("bmk_platform_halt@kernel.c:95 All is well in the universe.") {
child_proc_finished = 1;
if file_content.contains("@#$%PASSED%$#@") {
test_succeeded = 1;
}
else if file_content.contains("@#$%FAILED%$#@") {
test_succeeded = 0;
}
else {
panic!("Invalid test outcome!");
}
}
else { continue; }
use std::str::FromStr;
use std::fs::OpenOptions;
let mut lines = file_content.lines();
let mut search_finished = 0;
let mut test_name = String::new();
while search_finished == 0 {
let mut current_line = lines.next();
if current_line == None {
panic!("Test name not found in outputs.txt");
}
let current_line = current_line.unwrap();
println!("{}", current_line);
if current_line.contains("**TEST**") {
search_finished = 1;
test_name = String::from_str(lines.next().unwrap()).unwrap();
}
}
// let mut log_file = File::create("results_log.txt");
let mut log_file = OpenOptions::new().write(true).append(true).open("results_log.txt");
let mut log_file = match log_file {
Ok(the_file) => the_file,
Err(error) => { panic!("Creating-Opening log file failed with error -{}-", error); }
};
log_file.write_fmt(format_args!("******************************\n")).unwrap();
log_file.write_fmt(format_args!("Test time : {}\n", time::now_utc().ctime())).unwrap();
log_file.write_fmt(format_args!("Test name : {}\n", test_name)).unwrap();
if test_succeeded == 1 {
log_file.write_fmt(format_args!("Test result : PASSED\n")).unwrap();
}
else {
log_file.write_fmt(format_args!("Test result : FAILED\n")).unwrap();
}
log_file.write_fmt(format_args!("******************************")).unwrap();
}
println!("+ 5 secs");
if test_length == test_length_max {
let output = Command::new("kill")
.arg("-15")
.arg("--")
.arg(tester_proc.id().to_string())
.output()
.expect("failed to kill TO");
assert!(output.status.success());
panic!("Test Timed Out!");
}
}
// Terminate the test proc
let output = Command::new("kill")
.arg("-15")
.arg("--")
.arg(tester_proc.id().to_string())
.output()
.expect("failed to kill");
assert!(output.status.success());
assert!(test_succeeded == 1);
}
\ No newline at end of file
......@@ -1031,9 +1031,84 @@ macro_rules! build_and_run_test {
}
backend::emit_context(&vm);
// let output_name = stringify!($test_name).to_string()+"_"+stringify!($tester_name);
// let executable = aot::link_test_primordial(vec![stringify!($test_name).to_string(), stringify!($tester_name).to_string()], output_name.as_str(), &vm);
// aot::execute(executable);
aot::run_test(&vm, stringify!($test_name), stringify!($tester_name));
};
// When test name in mu IR is different from the name of rust function \
// which creates the vm
($test_name: ident, $tester_name: ident, $fnc_name: ident) => {
VM::start_logging_trace();
let vm = Arc::new($fnc_name());
let compiler = Compiler::new(CompilerPolicy::default(), &vm);
let func_id = vm.id_of(stringify!($tester_name));
{
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
vm.make_primordial_thread(func_id, true, vec![]);
let func_id = vm.id_of(stringify!($test_name));
{
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
backend::emit_context(&vm);
aot::run_test(&vm, stringify!($test_name), stringify!($tester_name));
};
// When the testee has one dependent function
//
($test_name: ident AND $dep_name: ident, $tester_name: ident) => {
VM::start_logging_trace();
let vm = Arc::new($test_name());
let compiler = Compiler::new(CompilerPolicy::default(), &vm);
let func_id = vm.id_of(stringify!($tester_name));
{
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
vm.make_primordial_thread(func_id, true, vec![]);
let func_id = vm.id_of(stringify!($test_name));
{
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
let func_id = vm.id_of(stringify!($dep_name));
{
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
backend::emit_context(&vm);
aot::run_test_2f(&vm, stringify!($test_name), stringify!($dep_name), stringify!($tester_name));
};
}
\ No newline at end of file
This diff is collapsed.
......@@ -24,17 +24,22 @@ use self::mu::vm::*;
use self::mu::testutil;
use mu::utils::LinkedHashMap;
use self::mu::compiler::*;
use self::mu::testutil::aot;
use std::sync::Arc;
#[test]
fn test_truncate_then_call() {
let lib = testutil::compile_fncs("truncate_then_call", vec!["truncate_then_call", "dummy_call"], &truncate_then_call);
unsafe {
let truncate_then_call : libloading::Symbol<unsafe extern fn(u64) -> u32> = lib.get(b"truncate_then_call").unwrap();
let res = truncate_then_call(1);
println!("truncate_then_call(1) = {}", res);
assert!(res == 1);
}
// let lib = testutil::compile_fncs("truncate_then_call", vec!["truncate_then_call", "dummy_call"], &truncate_then_call);
//
// unsafe {
// let truncate_then_call : libloading::Symbol<unsafe extern fn(u64) -> u32> = lib.get(b"truncate_then_call").unwrap();
//
// let res = truncate_then_call(1);
// println!("truncate_then_call(1) = {}", res);
// assert!(res == 1);
// }
build_and_run_test!(truncate_then_call AND dummy_call, truncate_then_call_test1);
}
fn truncate_then_call() -> VM {
......@@ -66,7 +71,7 @@ fn truncate_then_call() -> VM {
});
}
{
// {
// --- truncate_then_call ---
typedef! ((vm) funcref_to_dummy = mu_funcref(dummy_call_sig));
constdef!((vm) <funcref_to_dummy> funcref_dummy = Constant::FuncRef(dummy_call));
......@@ -105,7 +110,9 @@ fn truncate_then_call() -> VM {
define_func_ver!((vm) truncate_then_call_v1 (entry: blk_entry) {
blk_entry
});
}
// }
emit_test! ((vm) (truncate_then_call truncate_then_call_test1 truncate_then_call_test1_v1 Int,Int,EQ (sig, u64(1u64), u32(1u64))));
vm
}
\ No newline at end of file
......@@ -924,5 +924,71 @@ fn fp_arraysum() -> VM {
define_func_ver! ((vm) fp_arraysum_v1 (entry: blk_entry) {blk_entry, blk1, blk2, blk3});
// tester functions for array-sum test is defined here
//
// typedef! (($vm) int1 = mu_int(1));
// typedef! (($vm) int64t = mu_int(64));
// constdef! (($vm) <int64t> int64_pass = Constant::Int(0));
// constdef! (($vm) <int64t> int64_fail = Constant::Int(1));
// constdef! (($vm) <$ty1> Arg_0 = Constant::Vector(vec![]));
// constdef! (($vm) <$ty2> f64_1 = Constant::$Arg2Type($in2));
// constdef! (($vm) <$ty3> f64_2 = Constant::$Arg3Type($out));
//
// funcsig! (($vm) tester_sig = () -> ());
// funcdecl! (($vm) <tester_sig> $test_name);
// funcdef! (($vm) <tester_sig> $test_name VERSION $tester_name);
//
// ssa! (($vm, $tester_name) <$ty1> a);
// ssa! (($vm, $tester_name) <$ty1> b);
//
// typedef! (($vm) type_funcref = mu_funcref($test_sig));
// constdef! (($vm) <type_funcref> const_funcref = Constant::FuncRef($vm.id_of(stringify!($name))));
//
// // blk_entry
// consta! (($vm, $tester_name) f64_0_local = f64_0);
// consta! (($vm, $tester_name) f64_1_local = f64_1);
//
// block! (($vm, $tester_name) blk_entry);
//
// consta! (($vm, $tester_name) const_funcref_local = const_funcref);
// ssa! (($vm, $tester_name) <$ty3> result);
// inst! (($vm, $tester_name) blk_entry_call:
// result = EXPRCALL (CallConvention::Mu, is_abort: false) const_funcref_local (f64_0_local, f64_1_local)
// );
//
// consta! (($vm, $tester_name) f64_2_local = f64_2);
// consta! (($vm, $tester_name) int64_pass_local = int64_pass);
// consta! (($vm, $tester_name) int64_fail_local = int64_fail);
// ssa! (($vm, $tester_name) <int1> cmp_res);
// inst! (($vm, $tester_name) blk_entry_cmp:
// cmp_res = CMPOP (CmpOp::$CMPType) result f64_2_local
// );
//
// ssa! (($vm, $tester_name) <int64t> blk_entry_ret);
// inst! (($vm, $tester_name) blk_entry_inst_select:
// blk_entry_ret = SELECT cmp_res int64_pass_local int64_fail_local
// );
//
// inst! (($vm, $tester_name) blk_entry_inst_ret:
// SET_RETVAL blk_entry_ret
// );
// inst! (($vm, $tester_name) blk_entry_inst_exit:
// THREADEXIT
// );
//
// define_block! (($vm, $tester_name) blk_entry(a, b) {
// blk_entry_call,
// blk_entry_cmp,
// blk_entry_inst_select,
// blk_entry_inst_ret,
// blk_entry_inst_exit
// });
//
// define_func_ver! (($vm) $tester_name (entry: blk_entry) {
// blk_entry
// });
//
vm
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment