Commit 4e35ae29 authored by Isaac Oscar Gariano's avatar Isaac Oscar Gariano

Re added deleted tests.

Added support for generation of unscaled immediate memory offsets.
Fixed compilation errors.
Modified calling of the c 'exit' function in tests so that it will expect a int<64> instead of an int<32>.
Modified formating of various IR things (like Value's and Instructions) to be more easillly readable.
parent 93c4cc59
......@@ -7,7 +7,7 @@ Cargo.lock
*.log
*.DS_Store
*.swp
.idea
.idea
*.pyc
*.o
*.dylib
......
......@@ -576,8 +576,8 @@ pub struct Destination {
impl Destination {
fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
let mut ret = format!("{} with ", self.target);
ret.push('[');
let mut ret = format!("{}", self.target);
ret.push('(');
for i in 0..self.args.len() {
let ref arg = self.args[i];
ret.push_str(arg.debug_str(ops).as_str());
......@@ -585,7 +585,7 @@ impl Destination {
ret.push_str(", ");
}
}
ret.push(']');
ret.push(')');
ret
}
......
......@@ -667,7 +667,7 @@ impl fmt::Display for TreeNode {
match self.v {
TreeNode_::Value(ref pv) => pv.fmt(f),
TreeNode_::Instruction(ref inst) => {
write!(f, "+({})", inst)
write!(f, "{}", inst)
}
}
}
......@@ -777,16 +777,16 @@ impl fmt::Display for Value {
if DISPLAY_TYPE {
match self.v {
Value_::SSAVar(_) => {
write!(f, "+({} %{})", self.ty, self.hdr)
write!(f, "{}(%{})", self.ty, self.hdr)
},
Value_::Constant(ref c) => {
write!(f, "+({} {} @{})", self.ty, c, self.hdr)
write!(f, "{}({})", self.ty, c)
},
Value_::Global(ref ty) => {
write!(f, "+(GLOBAL {} @{})", ty, self.hdr)
write!(f, "{}(@{})", ty, self.hdr)
},
Value_::Memory(ref mem) => {
write!(f, "+(MEM {} %{})", mem, self.hdr)
write!(f, "{}(%{})", mem, self.hdr)
}
}
} else {
......@@ -798,10 +798,10 @@ impl fmt::Display for Value {
write!(f, "{}", c)
},
Value_::Global(_) => {
write!(f, "GLOBAL @{}", self.hdr)
write!(f, "@{}", self.hdr)
},
Value_::Memory(ref mem) => {
write!(f, "MEM {} %{}", mem, self.hdr)
write!(f, "{}(%{})", mem, self.hdr)
}
}
}
......@@ -1170,15 +1170,28 @@ impl PartialEq for MuEntityHeader {
}
}
const DISPLAY_ID : bool = false;
impl fmt::Display for MuEntityHeader {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.name().is_none() {
write!(f, "UNNAMED #{}", self.id)
if DISPLAY_ID {
if self.name().is_none() {
write!(f, "UNAMED #{}", self.id)
} else {
if PRINT_ABBREVIATE_NAME {
write!(f, "{} #{}", self.abbreviate_name().unwrap(), self.id)
} else {
write!(f, "{} #{}", self.name().unwrap(), self.id)
}
}
} else {
if PRINT_ABBREVIATE_NAME {
write!(f, "{} #{}", self.abbreviate_name().unwrap(), self.id)
if self.name().is_none() {
write!(f, "{}", self.id)
} else {
write!(f, "{} #{}", self.name().unwrap(), self.id)
if PRINT_ABBREVIATE_NAME {
write!(f, "{}", self.abbreviate_name().unwrap())
} else {
write!(f, "{}", self.name().unwrap())
}
}
}
}
......
......@@ -56,29 +56,10 @@ pub trait CodeGenerator {
prfop is a string (or an imm5)
PRFM PRFM_imm
(also look at load / store unscaled)
CAS/b-h (ARMv8.1 (check if this will work on Wolf)
CASP
SWP/-b-h (ARMv8.1 only)
LDADD/-b-h Add
LDCLR/-b-h Bit clear
LDEOR/-b-h Exclusive Or
LDSET/-b-h Set
LDMAX-b-h signed maximum
LDMIN/b-h sign minimum
LDUMAX/-b-h unsigned maximum
LDUMIN/-b-h unsigned minimum
STADD/-b-h Add
STCLR/-b-h
STEOR/-b-h
STSET/-b-h
STMAX/-b-h
STMIN/-b-h
STUMAX/-b-h
STUMIN/-b-
TODO:
LSLV, ASRV, LSRV ??
Cryptograhpy instructions??
NOTE:
with loads and stores the menmonic indicated may be given a suffix indicating the size and signenedness of the access
also b_cond's menmononic is 'B.cond'
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -1079,7 +1079,9 @@ pub fn bits_ones(n: usize) -> u64 {
pub fn is_valid_immediate_offset(val: i64, n : usize) -> bool {
use std;
let n = std::cmp::max(n, 8);
val >= 0 && (val as u64) % (n as u64) == 0 && ((val as u64)/(n as u64) < (1 << 12))
(val >= -(1 << 8) && val < (1 << 8)) || // Valid 9 bit signed unscaled offset
// Valid unsigned 12-bit scalled offset
(val >= 0 && (val as u64) % (n as u64) == 0 && ((val as u64)/(n as u64) < (1 << 12)))
}
#[inline(always)]
......
/*#![allow(unused_variables)]
#![allow(unused_variables)]
use compiler::backend::AOT_EMIT_CONTEXT_FILE;
use compiler::backend::RegGroup;
......@@ -3657,5 +3657,4 @@ pub fn spill_rewrite(
cf.mc().trace_mc();
spilled_scratch_temps
}
*/
\ No newline at end of file
}
\ No newline at end of file
......@@ -189,7 +189,7 @@ fn emit_muir_dot_inner(file: &mut File,
for (id, block) in f_content.blocks.iter() {
let block_name = block.name().unwrap();
// BBid [label = "name
file.write_fmt(format_args!("BB{} [label = \"{} ", *id, &block_name)).unwrap();
file.write_fmt(format_args!("BB{} [label = \"[{}]{} ", *id, *id, &block_name)).unwrap();
let block_content = block.content.as_ref().unwrap();
......
......@@ -104,9 +104,9 @@ impl Frame {
self.exception_callsites.push((callsite, dest));
}
#[cfg(target_arch = "x86_64")]
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
fn alloc_slot(&mut self, val: &P<Value>, vm: &VM) -> &FrameSlot {
// RBP is 16 bytes aligned, we are offsetting from RBP
// RBP/FP is 16 bytes aligned, we are offsetting from RBP/FP
// every value should be properly aligned
let backendty = vm.get_backend_type_info(val.ty.id());
......
mod test_vm_serialize;
extern crate rustc_serialize;
use test_ir::test_ir::factorial;
use mu::vm::*;
use std::sync::Arc;
use self::rustc_serialize::json;
use self::rustc_serialize::base64::ToBase64;
use self::rustc_serialize::hex::ToHex;
use self::rustc_serialize::base64::STANDARD;
#[test]
fn test_vm_serialize_factorial() {
VM::start_logging_trace();
let vm = Arc::new(factorial());
let serialized_json = json::encode(&vm).unwrap();
println!("JSON(len={}):", serialized_json.len());
println!("{}", serialized_json);
let base64 = serialized_json.as_bytes().to_base64(STANDARD);
println!("base64(len={}):", base64.len());
println!("{}", base64);
let hex = serialized_json.as_bytes().to_hex();
println!("hex(len={}):", hex.len());
println!("{}", hex);
let reconstruct_vm : VM = json::decode(&serialized_json).unwrap();
let serialized_again = json::encode(&reconstruct_vm).unwrap();
println!("JSON for reconstructed VM(len={}):", serialized_again.len());
println!("{}", serialized_again);
// check_string_eq_char_by_char(serialized, serialized_again);
}
#[allow(dead_code)]
fn check_string_eq_char_by_char(str1: String, str2: String) {
use std::cmp;
let min_len = cmp::min(str1.len(), str2.len());
println!("str1_len = {}, str2_len = {}", str1.len(), str2.len());
let b1 = str1.into_bytes();
let b2 = str2.into_bytes();
for i in 0..min_len {
if b1[i] != b2[i] {
println!("different here ({}):", i);
print!("str1: ..");
for j in 0..20 {
print!("{}", b1[i + j] as char);
}
println!("..");
print!("str2: ..");
for j in 0..20 {
print!("{}", b2[i + j] as char);
}
println!("..");
panic!("found difference in two strings");
}
}
}
mod test_pre_instsel;
mod test_instsel;
mod test_regalloc;
mod test_global;
mod test_compiler;
mod test_alloc;
mod test_exception;
mod test_thread;
mod test_floatingpoint;
mod test_int;
mod test_binop;
mod test_controlflow;
mod test_call;
mod test_mem_inst;
mod test_inline;
mod test_convop;
\ No newline at end of file
......@@ -46,12 +46,12 @@ fn test_ccall_exit() {
}
pub fn gen_ccall_exit(arg: P<TreeNode>, func_ver: &mut MuFunctionVersion, vm: &VM) -> Box<TreeNode> {
typedef! ((vm) int32 = mu_int(32));
funcsig! ((vm) exit_sig = (int32) -> ());
typedef! ((vm) int64 = mu_int(64));
funcsig! ((vm) exit_sig = (int64) -> ());
typedef! ((vm) ufp_exit = mu_ufuncptr(exit_sig));
// .const @exit = EXTERN SYMBOL "exit"
constdef! ((vm) <ufp_exit> const_exit = Constant::ExternSym(C("exit")));
constdef! ((vm) <ufp_exit> const_exit = Constant::ExternSym(C ("exit")));
consta! ((vm, func_ver) const_exit_local = const_exit);
inst! ((vm, func_ver) ret:
......
extern crate libloading as ll;
extern crate mu;
use test_ir::test_ir::sum;
use test_ir::test_ir::factorial;
use mu::testutil;
#[test]
fn test_factorial() {
let lib = testutil::compile_fnc("fac", &factorial);
unsafe {
let fac: ll::Symbol<unsafe extern fn (u64) -> u64> = lib.get(b"fac").unwrap();
println!("fac(10) = {}", fac(10));
assert!(fac(10) == 3628800);
}
}
#[test]
fn test_sum() {
let lib = testutil::compile_fnc("sum", &sum);
unsafe {
let sumptr: ll::Symbol<unsafe extern fn (u64) -> u64> = lib.get(b"sum").unwrap();
println!("sum(5) = {}", sumptr(5));
assert!(sumptr(5) == 15);
println!("sun(10) = {}", sumptr(10));
assert!(sumptr(10) == 55);
}
}
extern crate mu;
extern crate log;
extern crate libloading;
use self::mu::ast::types::*;
use self::mu::ast::ir::*;
use self::mu::ast::inst::*;
use self::mu::ast::op::*;
use self::mu::vm::*;
use self::mu::testutil;
use mu::utils::LinkedHashMap;
use std::sync::RwLock;
#[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);
}
}
fn truncate_then_call() -> VM {
let vm = VM::new_with_opts("init_mu --disable-inline");
typedef! ((vm) u64 = mu_int(64));
typedef! ((vm) u32 = mu_int(32));
funcsig! ((vm) dummy_call_sig = (u32) -> (u32));
funcdecl!((vm) <dummy_call_sig> dummy_call);
{
// --- dummy call ---
funcdef! ((vm) <dummy_call_sig> dummy_call VERSION dummy_call_v1);
// entry
block! ((vm, dummy_call_v1) blk_entry);
ssa! ((vm, dummy_call_v1) <u32> x);
inst! ((vm, dummy_call_v1) ret:
RET (x)
);
define_block!((vm, dummy_call_v1) blk_entry(x) {
ret
});
define_func_ver!((vm) dummy_call_v1 (entry: blk_entry) {
blk_entry
});
}
{
// --- truncate_then_call ---
typedef! ((vm) funcref_to_dummy = mu_funcref(dummy_call_sig));
constdef!((vm) <funcref_to_dummy> funcref_dummy = Constant::FuncRef(dummy_call));
funcsig! ((vm) sig = (u64) -> (u32));
funcdecl!((vm) <sig> truncate_then_call);
funcdef! ((vm) <sig> truncate_then_call VERSION truncate_then_call_v1);
// entry
block!((vm, truncate_then_call_v1) blk_entry);
ssa! ((vm, truncate_then_call_v1) <u64> arg);
// %arg_u32 = TRUNC <u64 u32> arg
ssa! ((vm, truncate_then_call_v1) <u32> arg_u32);
inst!((vm, truncate_then_call_v1) blk_entry_truncate:
arg_u32 = CONVOP (ConvOp::TRUNC) <u64 u32> arg
);
// %ret = CALL dummy_call (arg_u32)
ssa! ((vm, truncate_then_call_v1) <u32> res);
consta! ((vm, truncate_then_call_v1) funcref_dummy_local = funcref_dummy);
inst! ((vm, truncate_then_call_v1) blk_entry_call:
res = EXPRCALL (CallConvention::Mu, is_abort: false) funcref_dummy_local (arg_u32)
);
inst!((vm, truncate_then_call_v1) blk_entry_ret:
RET (arg)
);
define_block!((vm, truncate_then_call_v1) blk_entry(arg) {
blk_entry_truncate,
blk_entry_call,
blk_entry_ret
});
define_func_ver!((vm) truncate_then_call_v1 (entry: blk_entry) {
blk_entry
});
}
vm
}
\ No newline at end of file
extern crate libloading;
use mu::ast::types::*;
use mu::ast::ir::*;
use mu::ast::inst::*;
use mu::ast::op::*;
use mu::vm::*;
use mu::testutil;
use mu::utils::LinkedHashMap;
use std::sync::RwLock;
#[test]
fn test_inline_add_simple() {
let lib = testutil::compile_fncs("add_trampoline", vec!["add_trampoline", "add"], &inline_add);
unsafe {
let inline_add : libloading::Symbol<unsafe extern fn(u64, u64) -> u64> = lib.get(b"add_trampoline").unwrap();
let inline_add_1_1 = inline_add(1, 1);
println!("add(1, 1) = {}", inline_add_1_1);
assert!(inline_add_1_1 == 2);
}
}
fn inline_add() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
funcsig! ((vm) sig = (int64, int64) -> (int64));
funcdecl! ((vm) <sig> add);
{
// add
funcdef! ((vm) <sig> add VERSION add_v1);
block! ((vm, add_v1) blk_entry);
ssa! ((vm, add_v1) <int64> x);
ssa! ((vm, add_v1) <int64> y);
ssa! ((vm, add_v1) <int64> res);
inst! ((vm, add_v1) blk_entry_add:
res = BINOP (BinOp::Add) x y
);
inst! ((vm, add_v1) blk_entry_ret:
RET (res)
);
define_block! ((vm, add_v1) blk_entry(x, y) {blk_entry_add, blk_entry_ret});
define_func_ver!((vm) add_v1 (entry: blk_entry) {blk_entry});
}
{
// add_trampoline
typedef! ((vm) funcref_to_sig = mu_funcref(sig));
constdef! ((vm) <funcref_to_sig> funcref_add = Constant::FuncRef(add));
funcdecl! ((vm) <sig> add_trampoline);
funcdef! ((vm) <sig> add_trampoline VERSION add_trampoline_v1);
block! ((vm, add_trampoline_v1) tramp_blk_entry);
ssa! ((vm, add_trampoline_v1) <int64> tramp_x);
ssa! ((vm, add_trampoline_v1) <int64> tramp_y);
consta! ((vm, add_trampoline_v1) funcref_add_local = funcref_add);
ssa! ((vm, add_trampoline_v1) <int64> tramp_res);
inst! ((vm, add_trampoline_v1) tramp_blk_call:
tramp_res = EXPRCALL (CallConvention::Mu, is_abort: false) funcref_add_local (tramp_x, tramp_y)
);
inst! ((vm, add_trampoline_v1) tramp_blk_ret:
RET (tramp_res)
);
define_block! ((vm, add_trampoline_v1) tramp_blk_entry(tramp_x, tramp_y) {tramp_blk_call, tramp_blk_ret});
define_func_ver!((vm) add_trampoline_v1 (entry: tramp_blk_entry) {tramp_blk_entry});
}
vm
}
#[test]
fn test_inline_add_twice() {
let lib = testutil::compile_fncs("add_twice", vec!["add_twice", "add"], &inline_add_twice);
unsafe {
let add_twice : libloading::Symbol<unsafe extern fn(u64, u64, u64) -> u64> = lib.get(b"add_twice").unwrap();
let res = add_twice(1, 1, 1);
println!("add(1, 1, 1) = {}", res);
assert!(res == 3);
}
}
fn inline_add_twice() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
funcsig! ((vm) sig = (int64, int64) -> (int64));
funcdecl! ((vm) <sig> add);
{
// add
funcdef! ((vm) <sig> add VERSION add_v1);
block! ((vm, add_v1) blk_entry);
ssa! ((vm, add_v1) <int64> x);
ssa! ((vm, add_v1) <int64> y);
ssa! ((vm, add_v1) <int64> res);
inst! ((vm, add_v1) blk_entry_add:
res = BINOP (BinOp::Add) x y
);
inst! ((vm, add_v1) blk_entry_ret:
RET (res)
);
define_block! ((vm, add_v1) blk_entry(x, y) {blk_entry_add, blk_entry_ret});
define_func_ver!((vm) add_v1 (entry: blk_entry) {blk_entry});
}
{
// add_twice
typedef! ((vm) funcref_to_sig = mu_funcref(sig));
constdef! ((vm) <funcref_to_sig> funcref_add = Constant::FuncRef(add));
funcsig! ((vm) add_twice_sig = (int64, int64, int64) -> (int64));
funcdecl! ((vm) <add_twice_sig> add_twice);
funcdef! ((vm) <add_twice_sig> add_twice VERSION add_twice_v1);
block! ((vm, add_twice_v1) blk_entry);
ssa! ((vm, add_twice_v1) <int64> x);
ssa! ((vm, add_twice_v1) <int64> y);
ssa! ((vm, add_twice_v1) <int64> z);
consta! ((vm, add_twice_v1) funcref_add_local = funcref_add);
ssa! ((vm, add_twice_v1) <int64> add_twice_res1);
inst! ((vm, add_twice_v1) call:
add_twice_res1 = EXPRCALL (CallConvention::Mu, is_abort: false) funcref_add_local (x, y)
);
ssa! ((vm, add_twice_v1) <int64> add_twice_res2);
inst! ((vm, add_twice_v1) call2:
add_twice_res2 = EXPRCALL (CallConvention::Mu, is_abort: false) funcref_add_local (add_twice_res1, z)
);
inst! ((vm, add_twice_v1) ret:
RET (add_twice_res2)
);
define_block! ((vm, add_twice_v1) blk_entry(x, y, z) {call, call2, ret});
define_func_ver!((vm) add_twice_v1 (entry: blk_entry) {blk_entry});
}
vm
}
#[test]
fn test_inline_add_with_extra_norm_args() {
let lib = testutil::compile_fncs("inline_add_with_extra_norm_args", vec!["add_with_extra_norm_args", "add"], &inline_add_with_extra_norm_args);
unsafe {
let add_twice : libloading::Symbol<unsafe extern fn(u64, u64, u64) -> u64> = lib.get(b"add_with_extra_norm_args").unwrap();
let res = add_twice(1, 1, 1);
println!("add(1, 1, 1) = {}", res);
assert!(res == 103);
}
}
fn inline_add_with_extra_norm_args() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
funcsig! ((vm) sig = (int64, int64) -> (int64));
funcdecl! ((vm) <sig> add);
{
// add
funcdef! ((vm) <sig> add VERSION add_v1);
block! ((vm, add_v1) blk_entry);
ssa! ((vm, add_v1) <int64> x);
ssa! ((vm, add_v1) <int64> y);
ssa! ((vm, add_v1) <int64> res);
inst! ((vm, add_v1) blk_entry_add:
res = BINOP (BinOp::Add) x y
);
inst! ((vm, add_v1) blk_entry_ret:
RET (res)
);
define_block! ((vm, add_v1) blk_entry(x, y) {blk_entry_add, blk_entry_ret});
define_func_ver!((vm) add_v1 (entry: blk_entry) {blk_entry});
}
{
// inline_add_with_extra_norm_args
typedef! ((vm) funcref_to_sig = mu_funcref(sig));
constdef! ((vm) <funcref_to_sig> funcref_add = Constant::FuncRef(add));
constdef! ((vm) <int64> int64_0 = Constant::Int(0));
constdef! ((vm) <int64> int64_100 = Constant::Int(100));
funcsig! ((vm) sig_add_with_extra_norm_args = (int64, int64, int64) -> (int64));
funcdecl! ((vm) <sig_add_with_extra_norm_args> add_with_extra_norm_args);
funcdef! ((vm) <sig_add_with_extra_norm_args> add_with_extra_norm_args VERSION add_with_extra_norm_args_v1);
block! ((vm, add_with_extra_norm_args_v1) blk_entry);
ssa! ((vm, add_with_extra_norm_args_v1) <int64> x);
ssa! ((vm, add_with_extra_norm_args_v1) <int64> y);
ssa! ((vm, add_with_extra_norm_args_v1) <int64> arg);
block! ((vm, add_with_extra_norm_args_v1) blk_norm);
block! ((vm, add_with_extra_norm_args_v1) blk_exn);
consta! ((vm, add_with_extra_norm_args_v1) funcref_add_local = funcref_add);
consta! ((vm, add_with_extra_norm_args_v1) int64_100_local = int64_100);
ssa! ((vm, add_with_extra_norm_args_v1) <int64> res);
inst! ((vm, add_with_extra_norm_args_v1) call:
// 0 , 1, 2, 3 , 4 , 5
res = CALL (funcref_add_local, x, y, res, arg, int64_100_local) FUNC(0) (vec![1, 2]) CallConvention::Mu,
normal: blk_norm (vec![DestArg::Normal(3), DestArg::Normal(4), DestArg::Normal(5)]),
exc: blk_exn (vec![])
);