Commit bdea18c4 authored by qinsoon's avatar qinsoon

sext, zext, truncate

(throw, new not working)
parent 9262dfcc
Pipeline #68 failed with stage
in 18 minutes and 43 seconds
**/target/*
**/__pycache__/*
**/.cache/*
emit/*
**/temp/*
Cargo.lock
......
......@@ -64,6 +64,8 @@ echo "KERNEL: $KERNEL"
echo "ARCH: $MACH"
echo "---------"
rm emit/*
if [ "$OS" == "linux" ]; then
RUSTFLAGS=-Zincremental=target/incr-cache RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang-3.8 cargo test "$@"
elif [ "$OS" == "Darwin" ]; then
......
......@@ -35,6 +35,8 @@ lazy_static! {
pub static ref INTERNAL_TYPES : Vec<P<MuType>> = vec![
ADDRESS_TYPE.clone(),
UINT8_TYPE.clone(),
UINT16_TYPE.clone(),
UINT32_TYPE.clone(),
UINT64_TYPE.clone(),
DOUBLE_TYPE.clone()
......
......@@ -483,6 +483,107 @@ impl <'a> InstructionSelection {
_ => 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)
// https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
......
......@@ -12,32 +12,13 @@ use self::mu::compiler::*;
use std::sync::RwLock;
use std::sync::Arc;
use mu::testutil;
use mu::testutil::aot;
#[test]
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 {
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 {
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
}
\ 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