To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

Commit 8f2ff707 authored by John Zhang's avatar John Zhang
Browse files

Merge branch 'master' into jit-test

parents 4bfc9b22 d9758e2c
#!/bin/sh
RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test "$@"
RUSTFLAGS=-Zincremental=target/incr-cache RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test "$@"
......@@ -1375,36 +1375,79 @@ impl CodeGenerator for ASMCodeGen {
false
)
}
fn emit_add_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: add {}, {} -> {}", dest, src, dest);
let (reg1, id1, loc1) = self.prepare_reg(src, 4 + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest, 4 + 1 + reg1.len() + 1);
let asm = format!("addq {},{}", reg1, reg2);
fn emit_movsd_f64_f64 (&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: movsd {} -> {}", src, dest);
let (reg1, id1, loc1) = self.prepare_reg(src, 5 + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest, 5 + 1 + reg1.len() + 1);
let asm = format!("movsd {},{}", reg1, reg2);
self.add_asm_inst(
asm,
hashmap!{
id2 => vec![loc2.clone()]
id2 => vec![loc2]
},
hashmap!{
id1 => vec![loc1],
id2 => vec![loc2]
id1 => vec![loc1]
},
false
)
}
// load
fn emit_movsd_f64_mem64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: movsd {} -> {}", src, dest);
let (mem, uses) = self.prepare_mem(src, 5 + 1);
let (reg, id2, loc2) = self.prepare_reg(dest, 5 + 1 + mem.len() + 1);
let asm = format!("movsd {},{}", mem, reg);
self.add_asm_inst(
asm,
hashmap!{
id2 => vec![loc2]
},
uses,
true
)
}
// store
fn emit_movsd_mem64_f64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: movsd {} -> {}", src, dest);
let (reg, id1, loc1) = self.prepare_reg(src, 5 + 1);
let (mem, mut uses) = self.prepare_mem(dest, 5 + 1 + reg.len() + 1);
// the register we used for the memory location is counted as 'use'
// use the vec from mem as 'use' (push use reg from src to it)
if uses.contains_key(&id1) {
uses.get_mut(&id1).unwrap().push(loc1);
} else {
uses.insert(id1, vec![loc1]);
}
let asm = format!("movsd {},{}", reg, mem);
self.add_asm_inst(
asm,
hashmap!{},
uses,
true
)
}
fn emit_lea_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: lea {} -> {}", src, dest);
let (mem, uses) = self.prepare_mem(src, 4 + 1);
let (reg, id2, loc2) = self.prepare_reg(dest, 4 + 1 + mem.len() + 1);
let asm = format!("leaq {},{}", mem, reg);
self.add_asm_inst(
asm,
hashmap!{
......@@ -1412,16 +1455,16 @@ impl CodeGenerator for ASMCodeGen {
},
uses,
true
)
)
}
fn emit_and_r64_imm32(&mut self, dest: &P<Value>, src: i32) {
trace!("emit: and {}, {} -> {}", src, dest, dest);
let (reg1, id1, loc1) = self.prepare_reg(dest, 4 + 1 + 1 + src.to_string().len() + 1);
let asm = format!("andq ${},{}", src, reg1);
self.add_asm_inst(
asm,
hashmap!{
......@@ -1433,14 +1476,35 @@ impl CodeGenerator for ASMCodeGen {
false
)
}
fn emit_and_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: and {}, {} -> {}", src, dest, dest);
let (reg1, id1, loc1) = self.prepare_reg(src, 4 + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest, 4 + 1 + reg1.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest, 4 + 1 + reg1.len() + 1);
let asm = format!("andq {},{}", reg1, reg2);
self.add_asm_inst(
asm,
hashmap!{
id2 => vec![loc2.clone()]
},
hashmap!{
id1 => vec![loc1],
id2 => vec![loc2]
},
false
)
}
fn emit_add_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: add {}, {} -> {}", dest, src, dest);
let (reg1, id1, loc1) = self.prepare_reg(src, 4 + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest, 4 + 1 + reg1.len() + 1);
let asm = format!("addq {},{}", reg1, reg2);
self.add_asm_inst(
asm,
......@@ -1453,7 +1517,7 @@ impl CodeGenerator for ASMCodeGen {
},
false
)
}
}
fn emit_add_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: add {}, {} -> {}", dest, src, dest);
......@@ -1478,6 +1542,32 @@ impl CodeGenerator for ASMCodeGen {
false
)
}
fn emit_addsd_f64_f64 (&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: addsd {}, {} -> {}", dest, src, dest);
let (reg1, id1, loc1) = self.prepare_reg(src, 5 + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest, 5 + 1 + reg1.len() + 1);
let asm = format!("addsd {},{}", reg1, reg2);
self.add_asm_inst(
asm,
hashmap!{
id2 => vec![loc2.clone()]
},
hashmap!{
id1 => vec![loc1],
id2 => vec![loc2]
},
false
)
}
fn emit_addsd_f64_mem64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: addsd {}, {} -> {}", dest, src, dest);
unimplemented!()
}
fn emit_sub_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
trace!("emit: sub {}, {} -> {}", dest, src, dest);
......
......@@ -26,26 +26,33 @@ pub trait CodeGenerator {
fn emit_cmp_r64_imm32(&mut self, op1: &P<Value>, op2: i32);
fn emit_cmp_r64_mem64(&mut self, op1: &P<Value>, op2: &P<Value>);
fn emit_mov_r64_imm32(&mut self, dest: &P<Value>, src: i32);
fn emit_mov_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>); // load
fn emit_mov_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>);
fn emit_mov_mem64_r64(&mut self, dest: &P<Value>, src: &P<Value>); // store
fn emit_mov_r64_imm32 (&mut self, dest: &P<Value>, src: i32);
fn emit_mov_r64_mem64 (&mut self, dest: &P<Value>, src: &P<Value>); // load
fn emit_mov_r64_r64 (&mut self, dest: &P<Value>, src: &P<Value>);
fn emit_mov_mem64_r64 (&mut self, dest: &P<Value>, src: &P<Value>); // store
fn emit_mov_mem64_imm32(&mut self, dest: &P<Value>, src: i32);
fn emit_movsd_f64_f64 (&mut self, dest: &P<Value>, src: &P<Value>);
fn emit_movsd_f64_mem64(&mut self, dest: &P<Value>, src: &P<Value>); // load
fn emit_movsd_mem64_f64(&mut self, dest: &P<Value>, src: &P<Value>); // store
fn emit_lea_r64(&mut self, dest: &P<Value>, src: &P<Value>);
fn emit_and_r64_imm32(&mut self, dest: &P<Value>, src: i32);
fn emit_and_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>);
fn emit_and_r64_r64 (&mut self, dest: &P<Value>, src: &P<Value>);
fn emit_add_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>);
fn emit_add_r64_r64 (&mut self, dest: &P<Value>, src: &P<Value>);
fn emit_add_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>);
fn emit_add_r64_imm32(&mut self, dest: &P<Value>, src: i32);
fn emit_addsd_f64_f64 (&mut self, dest: &P<Value>, src: &P<Value>);
fn emit_addsd_f64_mem64(&mut self, dest: &P<Value>, src: &P<Value>);
fn emit_sub_r64_r64(&mut self, dest: &P<Value>, src: &P<Value>);
fn emit_sub_r64_mem64(&mut self, dest: &P<Value>, src: &P<Value>);
fn emit_sub_r64_imm32(&mut self, dest: &P<Value>, src: i32);
fn emit_mul_r64(&mut self, src: &P<Value>);
fn emit_mul_r64 (&mut self, src: &P<Value>);
fn emit_mul_mem64(&mut self, src: &P<Value>);
fn emit_jmp(&mut self, dest: MuName);
......
......@@ -171,7 +171,7 @@ impl <'a> InstructionSelection {
let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
let reg_op2 = self.emit_ireg(&ops[op2], f_content, f_context, vm);
let res_tmp = self.emit_get_result(node);
let res_tmp = self.get_result_value(node);
// mov op1, res
self.backend.emit_mov_r64_r64(&res_tmp, &reg_op1);
......@@ -182,7 +182,7 @@ impl <'a> InstructionSelection {
let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
let reg_op2 = self.node_iimm_to_i32(&ops[op2]);
let res_tmp = self.emit_get_result(node);
let res_tmp = self.get_result_value(node);
// mov op1, res
self.backend.emit_mov_r64_r64(&res_tmp, &reg_op1);
......@@ -196,7 +196,7 @@ impl <'a> InstructionSelection {
let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
let reg_op2 = self.emit_mem(&ops[op2]);
let res_tmp = self.emit_get_result(node);
let res_tmp = self.get_result_value(node);
// mov op1, res
self.backend.emit_mov_r64_r64(&res_tmp, &reg_op1);
......@@ -215,7 +215,7 @@ impl <'a> InstructionSelection {
let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
let reg_op2 = self.emit_ireg(&ops[op2], f_content, f_context, vm);
let res_tmp = self.emit_get_result(node);
let res_tmp = self.get_result_value(node);
// mov op1, res
self.backend.emit_mov_r64_r64(&res_tmp, &reg_op1);
......@@ -226,7 +226,7 @@ impl <'a> InstructionSelection {
let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
let imm_op2 = self.node_iimm_to_i32(&ops[op2]);
let res_tmp = self.emit_get_result(node);
let res_tmp = self.get_result_value(node);
// mov op1, res
self.backend.emit_mov_r64_r64(&res_tmp, &reg_op1);
......@@ -240,7 +240,7 @@ impl <'a> InstructionSelection {
let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
let mem_op2 = self.emit_mem(&ops[op2]);
let res_tmp = self.emit_get_result(node);
let res_tmp = self.get_result_value(node);
// mov op1, res
self.backend.emit_mov_r64_r64(&res_tmp, &reg_op1);
......@@ -284,7 +284,7 @@ impl <'a> InstructionSelection {
// put imm in a temporary
// here we use result reg as temporary
let res_tmp = self.emit_get_result(node);
let res_tmp = self.get_result_value(node);
self.backend.emit_mov_r64_imm32(&res_tmp, imm_op2);
self.backend.emit_mul_r64(&res_tmp);
......@@ -297,9 +297,41 @@ impl <'a> InstructionSelection {
}
// mov rax -> result
let res_tmp = self.emit_get_result(node);
let res_tmp = self.get_result_value(node);
self.backend.emit_mov_r64_r64(&res_tmp, &rax);
},
// floating point
op::BinOp::FAdd => {
if self.match_fpreg(&ops[op1]) && self.match_fpreg(&ops[op2]) {
trace!("emit add-fpreg-fpreg");
let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
let reg_op2 = self.emit_fpreg(&ops[op2], f_content, f_context, vm);
let res_tmp = self.get_result_value(node);
// movsd op1, res
self.backend.emit_movsd_f64_f64(&res_tmp, &reg_op1);
// add op2 res
self.backend.emit_addsd_f64_f64(&res_tmp, &reg_op2);
} else if self.match_fpreg(&ops[op1]) && self.match_mem(&ops[op2]) {
trace!("emit add-fpreg-mem");
let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
let mem_op2 = self.emit_mem(&ops[op2]);
let res_tmp = self.get_result_value(node);
// mov op1, res
self.backend.emit_movsd_f64_f64(&res_tmp, &reg_op1);
// sub op2 res
self.backend.emit_addsd_f64_mem64(&res_tmp, &mem_op2);
} else if self.match_mem(&ops[op1]) && self.match_fpreg(&ops[op2]) {
trace!("emit add-mem-fpreg");
unimplemented!();
} else {
unimplemented!()
}
}
_ => unimplemented!()
}
......@@ -321,7 +353,7 @@ impl <'a> InstructionSelection {
}
let resolved_loc = self.node_mem_to_value(loc_op, vm);
let res_temp = self.emit_get_result(node);
let res_temp = self.get_result_value(node);
if self.match_ireg(node) {
// emit mov(GPR)
......@@ -371,7 +403,7 @@ impl <'a> InstructionSelection {
let ops = inst.ops.read().unwrap();
let ref op = ops[op_index];
let res_tmp = self.emit_get_result(node);
let res_tmp = self.get_result_value(node);
let hdr_size = mm::objectmodel::OBJECT_HEADER_SIZE;
if hdr_size == 0 {
......@@ -440,7 +472,7 @@ impl <'a> InstructionSelection {
// put start as result
// ASM: mov %start -> %result
let tmp_res = self.emit_get_result(node);
let tmp_res = self.get_result_value(node);
self.backend.emit_mov_r64_r64(&tmp_res, &tmp_start);
// ASM jmp alloc_end
......@@ -533,8 +565,14 @@ impl <'a> InstructionSelection {
fn emit_load_base_offset (&mut self, dest: &P<Value>, base: &P<Value>, offset: i32, vm: &VM) {
let mem = self.make_memory_op_base_offset(base, offset, dest.ty.clone(), vm);
self.backend.emit_mov_r64_mem64(dest, &mem);
if dest.is_int_reg() {
self.backend.emit_mov_r64_mem64(dest, &mem);
} else if dest.is_fp_reg() {
self.backend.emit_movsd_f64_mem64(dest, &mem);
} else {
unimplemented!();
}
}
fn emit_store_base_offset (&mut self, base: &P<Value>, offset: i32, src: &P<Value>, vm: &VM) {
......@@ -929,7 +967,7 @@ impl <'a> InstructionSelection {
// unload arguments
let mut gpr_arg_count = 0;
// TODO: let mut fpr_arg_count = 0;
let mut fpr_arg_count = 0;
// initial stack arg is at RBP+16
// arg <- RBP + 16
// return addr
......@@ -949,7 +987,17 @@ impl <'a> InstructionSelection {
stack_arg_offset += arg_size as i32;
}
} else if arg.is_fp_reg() {
unimplemented!();
if fpr_arg_count < x86_64::ARGUMENT_FPRs.len() {
self.backend.emit_movsd_f64_f64(&arg, &x86_64::ARGUMENT_FPRs[fpr_arg_count]);
fpr_arg_count += 1;
} else {
// unload from stack
self.emit_load_base_offset(&arg, &x86_64::RBP.clone(), stack_arg_offset, vm);
// move stack_arg_offset by the size of 'arg'
let arg_size = vm.get_backend_type_info(arg.ty.id()).size;
stack_arg_offset += arg_size as i32;
}
} else {
// args that are not fp or int (possibly struct/array/etc)
unimplemented!();
......@@ -971,7 +1019,7 @@ impl <'a> InstructionSelection {
};
let mut gpr_ret_count = 0;
// TODO: let mut fpr_ret_count = 0;
let mut fpr_ret_count = 0;
for i in ret_val_indices {
let ref ret_val = ops[*i];
if self.match_ireg(ret_val) {
......@@ -984,6 +1032,11 @@ impl <'a> InstructionSelection {
self.backend.emit_mov_r64_imm32(&x86_64::RETURN_GPRs[gpr_ret_count], imm_ret_val);
gpr_ret_count += 1;
} else if self.match_fpreg(ret_val) {
let reg_ret_val = self.emit_fpreg(ret_val, f_content, f_context, vm);
self.backend.emit_movsd_f64_f64(&x86_64::RETURN_FPRs[fpr_ret_count], &reg_ret_val);
fpr_ret_count += 1;
} else {
unimplemented!();
}
......@@ -1061,7 +1114,7 @@ impl <'a> InstructionSelection {
let ref value = inst.value.as_ref().unwrap()[0];
if types::is_scalar(&value.ty) {
if value.is_int_reg() {
true
} else {
false
......@@ -1076,30 +1129,63 @@ impl <'a> InstructionSelection {
}
}
}
fn match_fpreg(&mut self, op: &TreeNode) -> bool {
match op.v {
TreeNode_::Instruction(ref inst) => {
if inst.value.is_some() {
if inst.value.as_ref().unwrap().len() > 1 {
return false;
}
let ref value = inst.value.as_ref().unwrap()[0];
if value.is_fp_reg() {
true
} else {
false
}
} else {
false
}
}
TreeNode_::Value(ref pv) => {
pv.is_fp_reg()
}
}
}
fn emit_ireg(&mut self, op: &P<TreeNode>, f_content: &FunctionContent, f_context: &mut FunctionContext, vm: &VM) -> P<Value> {
match op.v {
TreeNode_::Instruction(_) => {
self.instruction_select(op, f_content, f_context, vm);
self.emit_get_result(op)
self.get_result_value(op)
},
TreeNode_::Value(ref pv) => {
match pv.v {
Value_::Constant(_)
| Value_::Global(_)
| Value_::Memory(_) => panic!("expected ireg"),
Value_::SSAVar(_) => {
pv.clone()
},
Value_::SSAVar(_) => pv.clone(),
_ => panic!("expected ireg")
}
}
}
}
#[allow(unused_variables)]
fn match_fpreg(&mut self, op: &P<TreeNode>) -> bool {
unimplemented!()
fn emit_fpreg(&mut self, op: &P<TreeNode>, f_content: &FunctionContent, f_context: &mut FunctionContext, vm: &VM) -> P<Value> {
match op.v {
TreeNode_::Instruction(_) => {
self.instruction_select(op, f_content, f_context, vm);
self.get_result_value(op)
},
TreeNode_::Value(ref pv) => {
match pv.v {
Value_::SSAVar(_) => pv.clone(),
_ => panic!("expected fpreg")
}
}
}
}
fn match_iimm(&mut self, op: &P<TreeNode>) -> bool {
......@@ -1224,7 +1310,7 @@ impl <'a> InstructionSelection {
unimplemented!()
}
fn emit_get_result(&mut self, node: &TreeNode) -> P<Value> {
fn get_result_value(&mut self, node: &TreeNode) -> P<Value> {
match node.v {
TreeNode_::Instruction(ref inst) => {
if inst.value.is_some() {
......
......@@ -143,7 +143,9 @@ lazy_static!{
XMM1.clone()
];
pub static ref ARGUMENT_FPRs : [P<Value>; 6] = [
pub static ref ARGUMENT_FPRs : [P<Value>; 8] = [
XMM0.clone(),
XMM1.clone(),
XMM2.clone(),
XMM3.clone(),
XMM4.clone(),
......
......@@ -2,6 +2,8 @@ extern crate mu;
#[macro_use]
extern crate log;
extern crate simple_logger;
#[macro_use]
extern crate maplit;
mod test_ir;
mod test_compiler;
......
......@@ -5,4 +5,5 @@ mod test_global;
mod test_compiler;
mod test_alloc;
mod test_exception;
mod test_thread;
\ No newline at end of file
mod test_thread;
mod test_floatingpoint;
\ No newline at end of file
extern crate mu;
extern crate log;
extern crate simple_logger;
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::compiler::*;
use std::sync::RwLock;
use std::sync::Arc;
use aot;
#[test]
fn test_fp_add() {
simple_logger::init_with_level(log::LogLevel::Trace).ok();
let vm = Arc::new(fp_add());
let compiler = Compiler::new(CompilerPolicy::default(), vm.clone());
let func_id = vm.id_of("fp_add");