WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

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

Commit 38d18dda authored by qinsoon's avatar qinsoon
Browse files

start using 8/16/32 bits registers

1. compiler knows all the registers
2. but only 64bits register is a color (for reg alloc)
3. backend records the length of GPR for each operand during instruction
selection
4. after reg alloc, when replacing temp with a color, find corresponding
GPR for the length recorded before
parent 5c0bdb9f
......@@ -36,11 +36,11 @@ lazy_static! {
};
}
pub const MACHINE_ID_START : usize = 0;
pub const MACHINE_ID_END : usize = 100;
pub const MACHINE_ID_END : usize = 200;
pub const INTERNAL_ID_START: usize = 101;
pub const INTERNAL_ID_END : usize = 200;
pub const USER_ID_START : usize = 201;
pub const INTERNAL_ID_START: usize = 201;
pub const INTERNAL_ID_END : usize = 500;
pub const USER_ID_START : usize = 1001;
#[deprecated]
#[allow(dead_code)]
......
......@@ -75,6 +75,23 @@ impl MuType {
_ => None
}
}
pub fn get_int_length(&self) -> Option<usize> {
use types::MuType_::*;
match self.v {
Int(len) => Some(len),
Ref(_)
| IRef(_)
| WeakRef(_)
| UPtr(_)
| ThreadRef
| StackRef
| Tagref64
| FuncRef(_)
| UFuncPtr(_) => Some(64),
_ => None
}
}
}
pub type StructTag = MuName;
......@@ -496,6 +513,6 @@ pub struct MuFuncSig {
impl fmt::Display for MuFuncSig {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}] -> [{}]", vec_utils::as_str(&self.ret_tys), vec_utils::as_str(&self.arg_tys))
write!(f, "[{}] -> [{}]", vec_utils::as_str(&self.arg_tys), vec_utils::as_str(&self.ret_tys))
}
}
......@@ -7,6 +7,7 @@ use compiler::backend::RegGroup;
use utils::ByteSize;
use compiler::backend::x86_64;
use compiler::backend::x86_64::CodeGenerator;
use compiler::backend::{Reg, Mem};
use compiler::machine_code::MachineCode;
use vm::VM;
use runtime::ValueLocation;
......@@ -193,7 +194,8 @@ impl ASMCode {
let new_patchpoint = ASMLocation {
line: *location_map.get(&patchpoint.line).unwrap(),
index: patchpoint.index,
len: patchpoint.len
len: patchpoint.len,
oplen: patchpoint.oplen
};
ret.frame_size_patchpoints.push(new_patchpoint);
......@@ -363,7 +365,8 @@ impl MachineCode for ASMCode {
fn is_move(&self, index: usize) -> bool {
let inst = self.code.get(index);
match inst {
Some(inst) => inst.code.starts_with("mov"),
Some(inst) => inst.code.starts_with("mov")
&& !(inst.code.starts_with("movs") || inst.code.starts_with("movz")),
None => false
}
}
......@@ -389,36 +392,31 @@ impl MachineCode for ASMCode {
}
fn replace_reg(&mut self, from: MuID, to: MuID) {
let to_reg_tag : MuName = match backend::all_regs().get(&to) {
Some(reg) => reg.name().unwrap(),
None => panic!("expecting a machine register, but we are required to replace to {}", to)
};
let to_reg_string = "%".to_string() + &to_reg_tag;
for loc in self.get_define_locations(from) {
let ref mut inst_to_patch = self.code[loc.line];
for i in 0..loc.len {
// FIXME: why loop here?
string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len());
}
// pick the right reg based on length
let to_reg = x86_64::get_alias_for_length(to, loc.oplen);
let to_reg_tag = to_reg.name().unwrap();
let to_reg_string = "%".to_string() + &to_reg_tag;
string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len());
}
for loc in self.get_use_locations(from) {
let ref mut inst_to_patch = self.code[loc.line];
for i in 0..loc.len {
string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len());
}
// pick the right reg based on length
let to_reg = x86_64::get_alias_for_length(to, loc.oplen);
let to_reg_tag = to_reg.name().unwrap();
let to_reg_string = "%".to_string() + &to_reg_tag;
string_utils::replace(&mut inst_to_patch.code, loc.index, &to_reg_string, to_reg_string.len());
}
}
fn replace_define_tmp_for_inst(&mut self, from: MuID, to: MuID, inst: usize) {
let to_reg_string : MuName = match backend::all_regs().get(&to) {
Some(ref machine_reg) => {
let name = machine_reg.name().unwrap();
"%".to_string() + &name
},
None => REG_PLACEHOLDER.clone()
};
let to_reg_string : MuName = REG_PLACEHOLDER.clone();
let asm = &mut self.code[inst];
// if this reg is defined, replace the define
......@@ -426,9 +424,7 @@ impl MachineCode for ASMCode {
let define_locs = asm.defines.get(&from).unwrap().to_vec();
// replace temps
for loc in define_locs.iter() {
for i in 0..loc.len {
string_utils::replace(&mut asm.code, loc.index, &to_reg_string, to_reg_string.len());
}
string_utils::replace(&mut asm.code, loc.index, &to_reg_string, to_reg_string.len());
}
// remove old key, insert new one
......@@ -438,13 +434,7 @@ impl MachineCode for ASMCode {
}
fn replace_use_tmp_for_inst(&mut self, from: MuID, to: MuID, inst: usize) {
let to_reg_string : MuName = match backend::all_regs().get(&to) {
Some(ref machine_reg) => {
let name = machine_reg.name().unwrap();
"%".to_string() + &name
},
None => REG_PLACEHOLDER.clone()
};
let to_reg_string : MuName = REG_PLACEHOLDER.clone();
let asm = &mut self.code[inst];
......@@ -453,9 +443,7 @@ impl MachineCode for ASMCode {
let use_locs = asm.uses.get(&from).unwrap().to_vec();
// replace temps
for loc in use_locs.iter() {
for i in 0..loc.len {
string_utils::replace(&mut asm.code, loc.index, &to_reg_string, to_reg_string.len());
}
string_utils::replace(&mut asm.code, loc.index, &to_reg_string, to_reg_string.len());
}
// remove old key, insert new one
......@@ -666,15 +654,17 @@ impl ASMInst {
struct ASMLocation {
line: usize,
index: usize,
len: usize
len: usize,
oplen: usize,
}
impl ASMLocation {
fn new(line: usize, index: usize, len: usize) -> ASMLocation {
fn new(line: usize, index: usize, len: usize, oplen: usize) -> ASMLocation {
ASMLocation{
line: line,
index: index,
len: len
len: len,
oplen: oplen
}
}
}
......@@ -851,7 +841,20 @@ impl ASMCodeGen {
let str = self.asm_reg_op(op);
let len = str.len();
(str, op.extract_ssa_id().unwrap(), ASMLocation::new(self.line(), loc, len))
(str, op.extract_ssa_id().unwrap(), ASMLocation::new(self.line(), loc, len, check_op_len(op)))
}
fn prepare_fpreg(&self, op: &P<Value>, loc: usize) -> (String, MuID, ASMLocation) {
if cfg!(debug_assertions) {
match op.v {
Value_::SSAVar(_) => {},
_ => panic!("expecting register op")
}
}
let str = self.asm_reg_op(op);
let len = str.len();
(str, op.extract_ssa_id().unwrap(), ASMLocation::new(self.line(), loc, len, 64))
}
fn prepare_machine_reg(&self, op: &P<Value>) -> MuID {
......@@ -1105,417 +1108,370 @@ impl ASMCodeGen {
fn finish_code_sequence_asm(&mut self) -> Box<ASMCode> {
self.cur.take().unwrap()
}
}
#[inline(always)]
fn op_postfix(op_len: usize) -> &'static str {
match op_len {
8 => "b",
16 => "w",
32 => "l",
64 => "q",
_ => panic!("unexpected op size: {}", op_len)
}
}
fn internal_binop_no_def_r_r(&mut self, inst: &str, op1: &P<Value>, op2: &P<Value>) {
let len = check_op_len(op1);
// general instruction emission
macro_rules! cmp_r_r {
($func_name: ident, $inst: expr, $op_len: expr) => {
fn $func_name (&mut self, op1: &P<Value>, op2: &P<Value>) {
// with postfix
let inst = $inst.to_string() + &op_postfix($op_len);
trace!("emit: {} {} {}", inst, op1, op2);
// with postfix
let inst = inst.to_string() + &op_postfix(len);
trace!("emit: {} {} {}", inst, op1, op2);
let (reg1, id1, loc1) = self.prepare_reg(op1, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(op2, inst.len() + 1 + reg1.len() + 1);
let (reg1, id1, loc1) = self.prepare_reg(op1, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(op2, inst.len() + 1 + reg1.len() + 1);
let asm = format!("{} {},{}", inst, reg1, reg2);
let asm = format!("{} {},{}", inst, reg1, reg2);
self.add_asm_inst(
asm,
hashmap!{},
{
if id1 == id2 {
hashmap!{
id1 => vec![loc1, loc2]
}
} else {
hashmap!{
id1 => vec![loc1],
id2 => vec![loc2]
}
self.add_asm_inst(
asm,
hashmap!{},
{
if id1 == id2 {
hashmap!{
id1 => vec![loc1, loc2]
}
},
false
)
}
} else {
hashmap!{
id1 => vec![loc1],
id2 => vec![loc2]
}
}
},
false
)
}
}
macro_rules! cmp_imm_r {
($func_name: ident, $inst: expr, $op_len: expr, $imm_ty: ty) => {
fn $func_name (&mut self, op1: $imm_ty, op2: &P<Value>) {
let inst = $inst.to_string() + &op_postfix($op_len);
trace!("emit: {} {} {}", inst, op1, op2);
fn internal_binop_no_def_imm_r(&mut self, inst: &str, op1: i32, op2: &P<Value>) {
let len = check_op_len(op2);
let (reg2, id2, loc2) = self.prepare_reg(op2, inst.len() + 1 + 1 + op1.to_string().len() + 1);
let inst = inst.to_string() + &op_postfix(len);
trace!("emit: {} {} {}", inst, op1, op2);
let asm = format!("{} ${},{}", inst, op1, reg2);
let (reg2, id2, loc2) = self.prepare_reg(op2, inst.len() + 1 + 1 + op1.to_string().len() + 1);
self.add_asm_inst(
asm,
hashmap!{},
hashmap!{
id2 => vec![loc2]
},
false
)
let asm = format!("{} ${},{}", inst, op1, reg2);
}
self.add_asm_inst(
asm,
hashmap!{},
hashmap!{
id2 => vec![loc2]
},
false
)
}
}
macro_rules! cmp_mem_r {
($func_name: ident, $inst:expr, $op_len: expr) => {
fn $func_name (&mut self, op1: &P<Value>, op2: &P<Value>) {
let inst = $inst.to_string() + &op_postfix($op_len);
trace!("emit: {} {} {}", inst, op1, op2);
fn internal_binop_no_def_mem_r(&mut self, inst: &str, op1: &P<Value>, op2: &P<Value>) {
let len = check_op_len(op2);
let (mem, mut uses) = self.prepare_mem(op1, inst.len() + 1);
let (reg, id1, loc1) = self.prepare_reg(op2, inst.len() + 1 + mem.len() + 1);
let inst = inst.to_string() + &op_postfix(len);
trace!("emit: {} {} {}", inst, op1, op2);
let asm = format!("{} {},{}", inst, mem, reg);
let (mem, mut uses) = self.prepare_mem(op1, inst.len() + 1);
let (reg, id1, loc1) = self.prepare_reg(op2, inst.len() + 1 + mem.len() + 1);
// merge use vec
if uses.contains_key(&id1) {
let mut locs = uses.get_mut(&id1).unwrap();
vec_utils::add_unique(locs, loc1.clone());
} else {
uses.insert(id1, vec![loc1]);
}
let asm = format!("{} {},{}", inst, mem, reg);
self.add_asm_inst(
asm,
hashmap!{},
uses,
true
)
// merge use vec
if uses.contains_key(&id1) {
let mut locs = uses.get_mut(&id1).unwrap();
vec_utils::add_unique(locs, loc1.clone());
} else {
uses.insert(id1, vec![loc1]);
}
self.add_asm_inst(
asm,
hashmap!{},
uses,
true
)
}
}
macro_rules! binop_def_r_r {
($func_name: ident, $inst: expr, $op_len: expr) => {
fn $func_name (&mut self, dest: &P<Value>, src: &P<Value>) {
let inst = $inst.to_string() + &op_postfix($op_len);
trace!("emit: {} {}, {} -> {}", inst, src, dest, dest);
fn internal_binop_no_def_r_mem(&mut self, inst: &str, op1: &P<Value>, op2: &P<Value>) {
let len = check_op_len(op1);
let (reg1, id1, loc1) = self.prepare_reg(src, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest, inst.len() + 1 + reg1.len() + 1);
let inst = inst.to_string() + &op_postfix(len);
trace!("emit: {} {} {}", inst, op1, op2);
let asm = format!("{} {},{}", inst, reg1, reg2);
let (mem, mut uses) = self.prepare_mem(op2, inst.len() + 1);
let (reg, id1, loc1) = self.prepare_reg(op1, inst.len() + 1 + mem.len() + 1);
self.add_asm_inst(
asm,
hashmap!{
id2 => vec![loc2.clone()]
},
{
if id1 == id2 {
hashmap!{
id1 => vec![loc1, loc2]
}
} else {
hashmap!{
id1 => vec![loc1],
id2 => vec![loc2]
}
}
},
false
)
if uses.contains_key(&id1) {
let mut locs = uses.get_mut(&id1).unwrap();
vec_utils::add_unique(locs, loc1.clone());
} else {
uses.insert(id1, vec![loc1.clone()]);
}
}
}
macro_rules! binop_def_r_imm {
($func_name: ident, $inst: expr, $op_len: expr, $imm_ty: ty) => {
fn $func_name (&mut self, dest: &P<Value>, src: $imm_ty) {
let inst = $inst.to_string() + &op_postfix($op_len);
trace!("emit: {} {}, {} -> {}", inst, src, dest, dest);
let (reg1, id1, loc1) = self.prepare_reg(dest, inst.len() + 1 + 1 + src.to_string().len() + 1);
let asm = format!("{} {},{}", inst, mem, reg);
let asm = format!("{} ${},{}", inst, src, reg1);
self.add_asm_inst(
asm,
hashmap!{
id1 => vec![loc1.clone()]
},
hashmap!{
id1 => vec![loc1]
},
false
)
}
self.add_asm_inst(
asm,
hashmap!{},
uses,
true
)
}
}
macro_rules! binop_def_r_mem {
($func_name: ident, $inst: expr, $op_len: expr) => {
fn $func_name (&mut self, dest: &P<Value>, src: &P<Value>) {
let inst = $inst.to_string() + &op_postfix($op_len);
trace!("emit: {} {}, {} -> {}", inst, src, dest, dest);
fn internal_binop_def_r_r(&mut self, inst: &str, dest: &P<Value>, src: &P<Value>) {
let len = check_op_len(src);
let (mem, mut uses) = self.prepare_mem(src, inst.len() + 1);
let (reg, id1, loc1) = self.prepare_reg(dest, inst.len() + 1 + mem.len() + 1);
let inst = inst.to_string() + &op_postfix(len);
trace!("emit: {} {}, {} -> {}", inst, src, dest, dest);
if uses.contains_key(&id1) {
let mut locs = uses.get_mut(&id1).unwrap();
vec_utils::add_unique(locs, loc1.clone());
} else {
uses.insert(id1, vec![loc1.clone()]);
}
let (reg1, id1, loc1) = self.prepare_reg(src, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest, inst.len() + 1 + reg1.len() + 1);
let asm = format!("{} {},{}", inst, mem, reg);
let asm = format!("{} {},{}", inst, reg1, reg2);
self.add_asm_inst(
asm,
hashmap!{
id1 => vec![loc1]
},
uses,
true
)
}
self.add_asm_inst(
asm,
hashmap!{
id2 => vec![loc2.clone()]
},
{
if id1 == id2 {
hashmap!{
id1 => vec![loc1, loc2]
}
} else {
hashmap!{
id1 => vec![loc1],
id2 => vec![loc2]
}
}
},
false
)
}
}
macro_rules! mov_r_r {
($func_name: ident, $inst: expr, $op_len: expr) => {
fn $func_name (&mut self, dest: &P<Value>, src: &P<Value>) {
let inst = $inst.to_string() + &op_postfix($op_len);
trace!("emit: {} {} -> {}", inst, src, dest);
fn internal_binop_def_r_mr(&mut self, inst: &str, dest: &P<Value>, src: &P<Value>) {
let len = check_op_len(dest);
let (reg1, id1, loc1) = self.prepare_reg(src, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest, inst.len() + 1 + reg1.len() + 1);
let inst = inst.to_string() + &op_postfix(len);
trace!("emit: {} {}, {} -> {}", inst, src, dest, dest);
let asm = format!("{} {},{}", inst, reg1, reg2);
let mreg = self.prepare_machine_reg(src);
let mreg_name = src.name().unwrap();
let (reg2, id2, loc2) = self.prepare_reg(dest, inst.len() + 1 + 1 + mreg_name.len() + 1);
self.add_asm_inst(
asm,
hashmap!{
id2 => vec![loc2]
},
hashmap!{
id1 => vec![loc1]
},
false
)
}
let asm = format!("{} %{},{}", inst, mreg_name, reg2);
self.add_asm_inst(
asm,
hashmap!{
id2 => vec![loc2.clone()]
},
hashmap!{
id2 => vec![loc2],
mreg => vec![]
},
false
)
}
}
macro_rules! mov_r_imm {
($func_name: ident, $inst: expr, $op_len: expr, $imm_ty: ty) => {
fn $func_name (&mut self, dest: &P<Value>, src: $imm_ty) {
let inst = $inst.to_string() + &op_postfix($op_len);
trace!("emit: {} {} -> {}", inst, src, dest);
fn internal_binop_def_r_imm(&mut self, inst: &str, dest: &P<Value>, src: i32) {
let len = check_op_len(dest);
let (reg1, id1, loc1) = self.prepare_reg(dest, inst.len() + 1 + 1 + src.to_string().len() + 1);
let inst = inst.to_string() + &op_postfix(len);
trace!("emit: {} {}, {} -> {}", inst, src, dest, dest);
let asm = format!("{} ${},{}", inst, src, reg1);
let (reg1, id1, loc1) = self.prepare_reg(dest, inst.len() + 1 + 1 + src.to_string().len() + 1);
self.add_asm_inst(
asm,
hashmap!{
id1 => vec![loc1]
},
hashmap!{},
false
)
}
let asm = format!("{} ${},{}", inst, src, reg1);