GitLab will be partched to the latest stable version on 15 July 2020 at 2.00pm (AEDT) to 2.30pm (AEDT) due to Security Patch Availability. During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to us at N110 (b) CSIT building.

Commit bdea18c4 authored by qinsoon's avatar qinsoon

sext, zext, truncate

(throw, new not working)
parent 9262dfcc
**/target/* **/target/*
**/__pycache__/* **/__pycache__/*
**/.cache/*
emit/* emit/*
**/temp/* **/temp/*
Cargo.lock Cargo.lock
......
...@@ -64,6 +64,8 @@ echo "KERNEL: $KERNEL" ...@@ -64,6 +64,8 @@ echo "KERNEL: $KERNEL"
echo "ARCH: $MACH" echo "ARCH: $MACH"
echo "---------" echo "---------"
rm emit/*
if [ "$OS" == "linux" ]; then if [ "$OS" == "linux" ]; then
RUSTFLAGS=-Zincremental=target/incr-cache RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang-3.8 cargo test "$@" RUSTFLAGS=-Zincremental=target/incr-cache RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang-3.8 cargo test "$@"
elif [ "$OS" == "Darwin" ]; then elif [ "$OS" == "Darwin" ]; then
......
...@@ -35,6 +35,8 @@ lazy_static! { ...@@ -35,6 +35,8 @@ lazy_static! {
pub static ref INTERNAL_TYPES : Vec<P<MuType>> = vec![ pub static ref INTERNAL_TYPES : Vec<P<MuType>> = vec![
ADDRESS_TYPE.clone(), ADDRESS_TYPE.clone(),
UINT8_TYPE.clone(),
UINT16_TYPE.clone(),
UINT32_TYPE.clone(), UINT32_TYPE.clone(),
UINT64_TYPE.clone(), UINT64_TYPE.clone(),
DOUBLE_TYPE.clone() DOUBLE_TYPE.clone()
......
...@@ -483,6 +483,107 @@ impl <'a> InstructionSelection { ...@@ -483,6 +483,107 @@ impl <'a> InstructionSelection {
_ => unimplemented!() _ => unimplemented!()
} }
} }
Instruction_::ConvOp{operation, ref from_ty, ref to_ty, operand} => {
let ops = inst.ops.read().unwrap();
let ref op = ops[operand];
let extract_int_len = |x: &P<MuType>| {
match x.v {
MuType_::Int(len) => len,
_ => panic!("only expect int types, found: {}", x)
}
};
match operation {
op::ConvOp::TRUNC => {
// currently only use 64bits register
// so only keep what is needed in the register (set others to 0)
let from_ty_len = extract_int_len(from_ty);
let to_ty_len = extract_int_len(to_ty);
debug_assert!(from_ty_len > to_ty_len);
if self.match_ireg(op) {
let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
let tmp_res = self.get_result_value(node);
// ignoring from_ty for now (we use 64bits register for everything)
let mask = match to_ty_len {
8 => 0xFFi32,
16 => 0xFFFFi32,
32 => 0xFFFFFFFFi32,
_ => unimplemented!()
};
// mov op -> result
self.backend.emit_mov_r64_r64(&tmp_res, &tmp_op);
// and mask, result -> result
self.backend.emit_and_r64_imm32(&tmp_res, mask);
} else {
panic!("unexpected op (expect ireg): {}", op);
}
}
op::ConvOp::ZEXT => {
// currently only use 64bits register
// so set irrelevant bits to 0
let from_ty_len = extract_int_len(from_ty);
let to_ty_len = extract_int_len(to_ty);
debug_assert!(from_ty_len < to_ty_len);
if self.match_ireg(op) {
let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
let tmp_res = self.get_result_value(node);
let mask = match from_ty_len {
8 => 0xFFi32,
16 => 0xFFFFi32,
32 => 0xFFFFFFFFi32,
_ => unimplemented!()
};
// mov op -> result
self.backend.emit_mov_r64_r64(&tmp_res, &tmp_op);
// and mask result -> result
self.backend.emit_and_r64_imm32(&tmp_res, mask);
} else {
panic!("unexpected op (expect ireg): {}", op);
}
},
op::ConvOp::SEXT => {
// currently only use 64bits register
// we left shift the value, then arithmetic right shift back
let from_ty_len = extract_int_len(from_ty);
let to_ty_len = extract_int_len(to_ty);
debug_assert!(from_ty_len < to_ty_len);
let shift : i8 = (to_ty_len - from_ty_len) as i8;
if self.match_ireg(op) {
let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
let tmp_res = self.get_result_value(node);
// mov op -> result
self.backend.emit_mov_r64_r64(&tmp_res, &tmp_op);
// shl result, shift -> result
self.backend.emit_shl_r64_imm8(&tmp_res, shift);
// sar result, shift -> result
self.backend.emit_sar_r64_imm8(&tmp_res, shift);
} else {
panic!("unexpected op (expect ireg): {}", op)
}
}
_ => unimplemented!()
}
}
// load on x64 generates mov inst (no matter what order is specified) // load on x64 generates mov inst (no matter what order is specified)
// https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html // https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
......
...@@ -12,32 +12,13 @@ use self::mu::compiler::*; ...@@ -12,32 +12,13 @@ use self::mu::compiler::*;
use std::sync::RwLock; use std::sync::RwLock;
use std::sync::Arc; use std::sync::Arc;
use mu::testutil;
use mu::testutil::aot; use mu::testutil::aot;
#[test] #[test]
fn test_u8_add() { fn test_u8_add() {
simple_logger::init_with_level(log::LogLevel::Trace).ok(); let lib = testutil::compile_fnc("u8_add", &u8_add);
let vm = Arc::new(u8_add());
let compiler = Compiler::new(CompilerPolicy::default(), vm.clone());
let func_id = vm.id_of("u8_add");
{
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);
let dylib = aot::link_dylib(vec![Mu("u8_add")], "libu8_add.dylib");
let lib = libloading::Library::new(dylib.as_os_str()).unwrap();
unsafe { unsafe {
let u8_add : libloading::Symbol<unsafe extern fn(u8, u8) -> u8> = lib.get(b"u8_add").unwrap(); let u8_add : libloading::Symbol<unsafe extern fn(u8, u8) -> u8> = lib.get(b"u8_add").unwrap();
...@@ -115,5 +96,194 @@ fn u8_add() -> VM { ...@@ -115,5 +96,194 @@ fn u8_add() -> VM {
vm.define_func_version(func_ver); vm.define_func_version(func_ver);
vm
}
#[test]
fn test_truncate() {
let lib = testutil::compile_fnc("truncate", &truncate);
unsafe {
let truncate : libloading::Symbol<unsafe extern fn(u64) -> u64> = lib.get(b"truncate").unwrap();
let res = truncate(0xF01u64);
println!("truncate(0xF01) = {}", res);
assert!(res == 1);
}
}
fn truncate() -> VM {
let vm = VM::new();
// .typedef @u64 = int<64>
let type_def_u64 = vm.declare_type(vm.next_id(), MuType_::int(64));
vm.set_name(type_def_u64.as_entity(), Mu("u64"));
// .typedef @u8 = int<8>
let type_def_u8 = vm.declare_type(vm.next_id(), MuType_::int(8));
vm.set_name(type_def_u8.as_entity(), Mu("u8"));
// .funcsig @truncate_sig = (@u64) -> (@u64)
let truncate_sig = vm.declare_func_sig(vm.next_id(), vec![type_def_u64.clone()], vec![type_def_u64.clone()]);
vm.set_name(truncate_sig.as_entity(), Mu("truncate_sig"));
// .funcdecl @truncate <@truncate_sig>
let func_id = vm.next_id();
let func = MuFunction::new(func_id, truncate_sig.clone());
vm.set_name(func.as_entity(), Mu("truncate"));
vm.declare_func(func);
// .funcdef @truncate VERSION @truncate_v1 <@truncate_sig>
let mut func_ver = MuFunctionVersion::new(vm.next_id(), func_id, truncate_sig.clone());
vm.set_name(func_ver.as_entity(), Mu("truncate_v1"));
// %entry(<@u64> %a):
let mut blk_entry = Block::new(vm.next_id());
vm.set_name(blk_entry.as_entity(), Mu("entry"));
let blk_entry_a = func_ver.new_ssa(vm.next_id(), type_def_u8.clone());
vm.set_name(blk_entry_a.as_entity(), Mu("blk_entry_a"));
// %r = TRUNC @u64->@u8 %a
let blk_entry_r = func_ver.new_ssa(vm.next_id(), type_def_u8.clone());
vm.set_name(blk_entry_r.as_entity(), Mu("blk_entry_r"));
let blk_entry_truncate = func_ver.new_inst(Instruction{
hdr: MuEntityHeader::unnamed(vm.next_id()),
value: Some(vec![blk_entry_r.clone_value()]),
ops: RwLock::new(vec![blk_entry_a.clone()]),
v: Instruction_::ConvOp{
operation: ConvOp::TRUNC,
from_ty: type_def_u64.clone(),
to_ty: type_def_u8.clone(),
operand: 0
}
});
// %r2 = ZEXT @u8->@u64 %r
let blk_entry_r2 = func_ver.new_ssa(vm.next_id(), type_def_u64.clone());
vm.set_name(blk_entry_r2.as_entity(), Mu("blk_entry_r2"));
let blk_entry_zext = func_ver.new_inst(Instruction{
hdr: MuEntityHeader::unnamed(vm.next_id()),
value: Some(vec![blk_entry_r2.clone_value()]),
ops: RwLock::new(vec![blk_entry_r.clone()]),
v: Instruction_::ConvOp {
operation: ConvOp::ZEXT,
from_ty: type_def_u8.clone(),
to_ty: type_def_u64.clone(),
operand: 0
}
});
// RET %r2
let blk_entry_term = func_ver.new_inst(Instruction{
hdr: MuEntityHeader::unnamed(vm.next_id()),
value: None,
ops: RwLock::new(vec![blk_entry_r2.clone()]),
v: Instruction_::Return(vec![0])
});
blk_entry.content = Some(BlockContent{
args: vec![blk_entry_a.clone_value()],
exn_arg: None,
body: vec![blk_entry_truncate, blk_entry_zext, blk_entry_term],
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: hashmap!{
blk_entry.id() => blk_entry
}
});
vm.define_func_version(func_ver);
vm
}
#[test]
fn test_sext() {
let lib = testutil::compile_fnc("sext", &sext);
unsafe {
let sext : libloading::Symbol<unsafe extern fn(i8) -> i64> = lib.get(b"sext").unwrap();
let res = sext(-1);
println!("truncate(-1) = {}", res);
assert!(res == -1);
}
}
fn sext() -> VM {
let vm = VM::new();
// .typedef @i8 = int<8>
let type_def_i8 = vm.declare_type(vm.next_id(), MuType_::int(8));
vm.set_name(type_def_i8.as_entity(), Mu("i8"));
// .typedef @i64 = int<64>
let type_def_i64 = vm.declare_type(vm.next_id(), MuType_::int(64));
vm.set_name(type_def_i64.as_entity(), Mu("i64"));
// .funcsig @sext_sig = (@i8) -> (@i64)
let sext_sig = vm.declare_func_sig(vm.next_id(), vec![type_def_i64.clone()], vec![type_def_i8.clone()]);
vm.set_name(sext_sig.as_entity(), Mu("sext_sig"));
// .funcdecl @sext <@sext_sig>
let func_id = vm.next_id();
let func = MuFunction::new(func_id, sext_sig.clone());
vm.set_name(func.as_entity(), Mu("sext"));
vm.declare_func(func);
// .funcdef @sext VERSION @sext_v1 <@sext_sig>
let mut func_ver = MuFunctionVersion::new(vm.next_id(), func_id, sext_sig.clone());
vm.set_name(func_ver.as_entity(), Mu("sext_v1"));
// %entry(<@i8> %a):
let mut blk_entry = Block::new(vm.next_id());
vm.set_name(blk_entry.as_entity(), Mu("entry"));
let blk_entry_a = func_ver.new_ssa(vm.next_id(), type_def_i8.clone());
vm.set_name(blk_entry_a.as_entity(), Mu("blk_entry_a"));
// %r = SEXT @i8->@i64 %a
let blk_entry_r = func_ver.new_ssa(vm.next_id(), type_def_i64.clone());
vm.set_name(blk_entry_r.as_entity(), Mu("blk_entry_r"));
let blk_entry_add = func_ver.new_inst(Instruction{
hdr: MuEntityHeader::unnamed(vm.next_id()),
value: Some(vec![blk_entry_r.clone_value()]),
ops: RwLock::new(vec![blk_entry_a.clone()]),
v: Instruction_::ConvOp{
operation: ConvOp::SEXT,
from_ty: type_def_i8.clone(),
to_ty: type_def_i64.clone(),
operand: 0
}
});
// RET %r
let blk_entry_term = func_ver.new_inst(Instruction{
hdr: MuEntityHeader::unnamed(vm.next_id()),
value: None,
ops: RwLock::new(vec![blk_entry_r.clone()]),
v: Instruction_::Return(vec![0])
});
blk_entry.content = Some(BlockContent{
args: vec![blk_entry_a.clone_value()],
exn_arg: None,
body: vec![blk_entry_add, blk_entry_term],
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: hashmap!{
blk_entry.id() => blk_entry
}
});
vm.define_func_version(func_ver);
vm vm
} }
\ No newline at end of file
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