Commit 841d47a1 authored by Yi Lin's avatar Yi Lin

Merge branch 'aarch64' into 'master'

Merge aarch64 into master

See merge request !10
parents 99a65c69 f9dcc877
Pipeline #573 passed with stages
in 58 minutes and 36 seconds
......@@ -21,6 +21,7 @@ ast = {path = "src/ast"}
utils = {path = "src/utils"}
gc = {path = "src/gc"}
field-offset = "0.1.1"
libloading = "0.3"
lazy_static = "0.1.15"
......@@ -34,4 +35,5 @@ time = "0.1.34"
maplit = "0.1.4"
docopt = "0.6"
petgraph = "0.4.1"
extprim = "*"
\ No newline at end of file
extprim = "*"
num-traits = "*"
......@@ -735,6 +735,14 @@ impl Value {
})
}
pub fn is_int_ex_const(&self) -> bool {
match self.v {
Value_::Constant(Constant::IntEx(_)) => true,
_ => false
}
}
pub fn is_int_const(&self) -> bool {
match self.v {
Value_::Constant(Constant::Int(_)) => true,
......@@ -742,7 +750,13 @@ impl Value {
_ => false
}
}
pub fn is_fp_const(&self) -> bool {
match self.v {
Value_::Constant(Constant::Float(_)) => true,
Value_::Constant(Constant::Double(_)) => true,
_ => false
}
}
pub fn extract_int_const(&self) -> u64 {
match self.v {
Value_::Constant(Constant::Int(val)) => val,
......@@ -751,6 +765,13 @@ impl Value {
}
}
pub fn extract_int_ex_const(&self) -> Vec<u64> {
match self.v {
Value_::Constant(Constant::IntEx(ref val)) => val.clone(),
_ => panic!("expect int ex const")
}
}
pub fn extract_ssa_id(&self) -> Option<MuID> {
match self.v {
Value_::SSAVar(id) => Some(id),
......
......@@ -210,7 +210,7 @@ impl CmpOp {
FUGT => FULT,
FULT => FUGT,
_ => self, // all other comparisons are reflexive
_ => self, // all other comparisons are symmetric
}
}
pub fn invert(self) -> CmpOp {
......@@ -256,6 +256,18 @@ impl CmpOp {
FTRUE => FFALSE,
}
}
// gets the unsigned version of the comparison
pub fn get_unsigned(self) -> CmpOp {
use op::CmpOp::*;
match self {
SGE => UGE,
SLT => ULT,
SGT => UGT,
SLE => ULE,
_ => self,
}
}
pub fn is_signed(self) -> bool {
use op::CmpOp::*;
match self {
......@@ -263,6 +275,14 @@ impl CmpOp {
_ => false
}
}
pub fn is_symmetric(self) -> bool {
use op::CmpOp::*;
match self {
EQ | NE | FORD| FUNO| FUNE | FUEQ | FONE | FOEQ => true,
_ => false
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
......
......@@ -16,11 +16,9 @@ use utils::LinkedHashMap;
use ast::ptr::P;
use ast::ir::*;
use ast::types::*;
use std::str;
use std::usize;
use std::slice::Iter;
use std::ops;
use std::collections::HashSet;
......@@ -96,16 +94,6 @@ impl ASMCode {
panic!("didnt find any block for inst {}", inst)
}
fn get_block_by_start_inst(&self, inst: usize) -> Option<&ASMBlock> {
for block in self.blocks.values() {
if block.start_inst == inst {
return Some(block);
}
}
None
}
fn rewrite_insert(
&self,
insert_before: LinkedHashMap<usize, Vec<Box<ASMCode>>>,
......@@ -269,20 +257,8 @@ impl ASMCode {
// control flow analysis
let n_insts = self.number_of_insts();
let ref blocks = self.blocks;
let ref mut asm = self.code;
let block_start = {
let mut ret = vec![];
for block in blocks.values() {
if TRACE_CFA {
trace!("Block starts at {}", block.start_inst);
}
ret.push(block.start_inst);
}
ret
};
for i in 0..n_insts {
if TRACE_CFA {
trace!("---inst {}---", i);
......@@ -896,21 +872,6 @@ impl ASMInst {
spill_info: spill_info
}
}
fn nop() -> ASMInst {
ASMInst {
code: "".to_string(),
defines: LinkedHashMap::new(),
uses: LinkedHashMap::new(),
is_symbol: false,
is_mem_op_used: false,
preds: vec![],
succs: vec![],
branch: ASMBranchTarget::None,
spill_info: None
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
......@@ -993,14 +954,7 @@ impl ASMCodeGen {
self.cur().code.len()
}
fn add_asm_label(&mut self, code: String) {
let l = self.line();
trace!("emit: {}", code);
self.cur_mut().code.push(ASMInst::symbolic(code));
}
fn add_asm_block_label(&mut self, code: String, block_name: MuName) {
let l = self.line();
trace!("emit: [{}]{}", block_name, code);
self.cur_mut().code.push(ASMInst::symbolic(code));
}
......@@ -1010,10 +964,6 @@ impl ASMCodeGen {
self.cur_mut().code.push(ASMInst::symbolic(code));
}
fn prepare_machine_regs(&self, regs: Iter<P<Value>>) -> Vec<MuID> {
regs.map(|x| self.prepare_machine_reg(x)).collect()
}
fn add_asm_call(&mut self, code: String, potentially_excepting: Option<MuName>, target: Option<(MuID, ASMLocation)>) {
// a call instruction will use all the argument registers
// do not need
......@@ -1057,22 +1007,6 @@ impl ASMCodeGen {
}, None)
}
fn add_asm_ret(&mut self, code: String) {
// return instruction does not use anything (not RETURN REGS)
// otherwise it will keep RETURN REGS alive
// and if there is no actual move into RETURN REGS, it will keep RETURN REGS for alive for very long
// and prevents anything using those regsiters
self.add_asm_inst_internal(code, linked_hashmap! {}, linked_hashmap! {}, false, ASMBranchTarget::Return, None);
}
fn add_asm_branch(&mut self, code: String, target: MuName) {
self.add_asm_inst_internal(code, linked_hashmap! {}, linked_hashmap! {}, false, ASMBranchTarget::Unconditional(target), None);
}
fn add_asm_branch2(&mut self, code: String, target: MuName) {
self.add_asm_inst_internal(code, linked_hashmap! {}, linked_hashmap! {}, false, ASMBranchTarget::Conditional(target), None);
}
fn add_asm_inst(
&mut self,
code: String,
......@@ -1113,7 +1047,6 @@ impl ASMCodeGen {
target: ASMBranchTarget,
spill_info: Option<SpillMemInfo>)
{
let line = self.line();
trace!("asm: {}", code);
trace!(" defines: {:?}", defines);
trace!(" uses: {:?}", uses);
......@@ -1136,30 +1069,6 @@ impl ASMCodeGen {
(str, op.extract_ssa_id().unwrap(), ASMLocation::new(self.line(), loc, len, check_op_len(&op.ty)))
}
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 {
if cfg!(debug_assertions) {
match op.v {
Value_::SSAVar(_) => {},
_ => panic!("expecting machine register op")
}
}
op.extract_ssa_id().unwrap()
}
fn prepare_mem(&self, op: &P<Value>, loc: usize) -> (String, LinkedHashMap<MuID, Vec<ASMLocation>>) {
if cfg!(debug_assertions) {
match op.v {
......@@ -1203,7 +1112,9 @@ impl ASMCodeGen {
result_str.push_str(",");
let n = offset.ty.get_int_length().unwrap();
let shift_type =
if n == 64 { if signed { "SXTX" } else { "LSL" } } else if n == 32 { if signed { "SXTW" } else { "UXTW" } } else { panic!("Unexpected size for offset register") };
if n == 64 { if signed { "SXTX" } else { "LSL" } }
else if n == 32 { if signed { "SXTW" } else { "UXTW" } }
else { panic!("Unexpected size for offset register") };
result_str.push_str(&shift_type);
result_str.push_str(" #");
......@@ -1426,6 +1337,23 @@ impl ASMCodeGen {
)
}
fn internal_binop_str(&mut self, inst: &str, dest: &P<Value>, src1: &P<Value>, src2: &str) {
let inst = inst.to_string();
trace!("emit: \t{} {}, {} -> {}", inst, src1, src2, dest);
let (reg1, id1, loc1) = self.prepare_reg(dest, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(src1, inst.len() + 1 + reg1.len() + 1);
let asm = format!("{} {},{},#{}", inst, reg1, reg2, src2);
self.add_asm_inst(
asm,
ignore_zero_register(id1, vec![loc1]),
ignore_zero_register(id2, vec![loc2]),
false
)
}
// dest <= inst(src1, src2)
fn internal_unop_shift(&mut self, inst: &str, dest: &P<Value>, src: &P<Value>, shift: &str, amount: u8) {
let inst = inst.to_string();
......@@ -1781,7 +1709,6 @@ impl ASMCodeGen {
}
};
trace!("emit: \t{} {} -> {}", inst, src, dest);
let (reg, id, loc) = self.prepare_reg(dest, inst.len() + 1);
......@@ -1819,8 +1746,8 @@ impl ASMCodeGen {
let inst = inst.to_string();
trace!("emit: \t{} {} -> {},{}", inst, src, dest1, dest2);
let (reg1, id1, loc1) = self.prepare_reg(dest1, 3 + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest2, 3 + 1 + reg1.len() + 1);
let (reg1, id1, loc1) = self.prepare_reg(dest1, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest2, inst.len() + 1 + reg1.len() + 1);
let (mem, uses) = self.prepare_mem(src, inst.len() + 1 + reg1.len() + 1 + reg2.len() + 1);
let asm = format!("{} {},{},{}", inst, reg1, reg2, mem);
......@@ -1931,8 +1858,8 @@ impl ASMCodeGen {
let inst = inst.to_string();
trace!("emit: \t{} {},{} -> {}", inst, src1, src2, dest);
let (reg1, id1, loc1) = self.prepare_reg(src2, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(src1, inst.len() + 1 + reg1.len() + 1);
let (reg1, id1, loc1) = self.prepare_reg(src1, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(src2, inst.len() + 1 + reg1.len() + 1);
let (mem, mut uses) = self.prepare_mem(dest, inst.len() + 1 + reg1.len() + 1 + reg2.len() + 1);
if is_zero_register_id(id1) {
......@@ -1968,8 +1895,8 @@ impl ASMCodeGen {
trace!("emit: \t{} {},{} -> {},{}", inst, src1, src2, dest, status);
let (reg1, id1, loc1) = self.prepare_reg(status, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(src2, inst.len() + 1 + reg1.len() + 1);
let (reg3, id3, loc3) = self.prepare_reg(src1, inst.len() + 1 + reg1.len() + 1 + reg2.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(src1, inst.len() + 1 + reg1.len() + 1);
let (reg3, id3, loc3) = self.prepare_reg(src2, inst.len() + 1 + reg1.len() + 1 + reg2.len() + 1);
let (mem, mut uses) = self.prepare_mem(dest, inst.len() + 1 + reg1.len() + 1 + reg2.len() + 1 + reg3.len() + 1);
if is_zero_register_id(id2) {
......@@ -2004,19 +1931,6 @@ impl ASMCodeGen {
fn emit_str_spill(&mut self, dest: Mem, src: Reg) { self.internal_store("STR", dest, src, true, false); }
}
// Only used for loads and stores
#[inline(always)]
fn op_postfix(op_len: usize) -> &'static str {
match op_len {
1 => "B",
8 => "B",
16 => "H",
32 => "",
64 => "",
_ => panic!("unexpected op size: {}", op_len)
}
}
impl CodeGenerator for ASMCodeGen {
fn start_code(&mut self, func_name: MuName, entry: MuName) -> ValueLocation {
self.cur = Some(Box::new(ASMCode {
......@@ -2172,23 +2086,28 @@ impl CodeGenerator for ASMCodeGen {
}
}
fn add_cfi_sections(&mut self, arg: &str) { self.add_asm_symbolic(format!(".cfi_sections {}", arg)); }
fn add_cfi_startproc(&mut self) {
self.add_asm_symbolic("\t.cfi_startproc".to_string());
self.add_asm_symbolic(".cfi_startproc".to_string());
}
fn add_cfi_endproc(&mut self) {
self.add_asm_symbolic("\t.cfi_endproc".to_string());
self.add_asm_symbolic(".cfi_endproc".to_string());
}
fn add_cfi_def_cfa_register(&mut self, reg: Reg) {
let reg = self.asm_reg_op(reg);
self.add_asm_symbolic(format!("\t.cfi_def_cfa_register {}", reg));
self.add_asm_symbolic(format!(".cfi_def_cfa_register {}", reg));
}
fn add_cfi_def_cfa_offset(&mut self, offset: i32) {
self.add_asm_symbolic(format!("\t.cfi_def_cfa_offset {}", offset));
self.add_asm_symbolic(format!(".cfi_def_cfa_offset {}", offset));
}
fn add_cfi_def_cfa(&mut self, reg: Reg, offset: i32) {
let reg = self.asm_reg_op(reg);
self.add_asm_symbolic(format!(".cfi_def_cfa {}, {}", reg, offset));
}
fn add_cfi_offset(&mut self, reg: Reg, offset: i32) {
let reg = self.asm_reg_op(reg);
self.add_asm_symbolic(format!("\t.cfi_offset {}, {}", reg, offset));
self.add_asm_symbolic(format!(".cfi_offset {}, {}", reg, offset));
}
fn emit_frame_grow(&mut self) {
......@@ -2222,6 +2141,8 @@ impl CodeGenerator for ASMCodeGen {
)
}
fn emit_add_str(&mut self, dest: Reg, src1: Reg, src2: &str) {self.internal_binop_str("ADD", dest, src1, src2)}
// Pushes a pair of registers on the givne stack (uses the STP instruction)
fn emit_push_pair(&mut self, src1: &P<Value>, src2: &P<Value>, stack: &P<Value>) {
trace!("emit: \tpush_pair {},{} -> {}[-8,-16]", src1, src2, stack);
......@@ -2424,7 +2345,13 @@ impl CodeGenerator for ASMCodeGen {
trace!("emit: \tFMOV {} -> {}", src, dest);
let (reg1, id1, loc1) = self.prepare_reg(dest, 4 + 1);
let asm = format!("FMOV {},#{}", reg1, src);
// GCC complains if the immediate argument has no decimal part (it will treat it as an integer)
// (e.g. #1 is an error, but #1.0 is not)
let asm = if src == src.trunc() { // src is an integer, append '.0'
format!("FMOV {},#{}.0", reg1, src)
} else {
format!("FMOV {},#{}", reg1, src)
};
self.add_asm_inst(
asm,
......@@ -2745,10 +2672,10 @@ pub fn emit_code(fv: &mut MuFunctionVersion, vm: &VM) {
Ok(file) => file
};
file.write("\t.arch armv8-a\n".as_bytes()).unwrap();
file.write(".arch armv8-a\n".as_bytes()).unwrap();
// constants in text section
file.write("\t.text\n".as_bytes()).unwrap();
file.write(".text\n".as_bytes()).unwrap();
write_const_min_align(&mut file);
......@@ -2784,7 +2711,7 @@ fn write_const_min_align(f: &mut File) {
#[cfg(target_os = "linux")]
fn write_align(f: &mut File, align: ByteSize) {
use std::io::Write;
f.write_fmt(format_args!("\t.balign {}\n", check_min_align(align))).unwrap();
f.write_fmt(format_args!(".balign {}\n", check_min_align(align))).unwrap();
}
fn write_const(f: &mut File, constant: P<Value>, loc: P<Value>) {
......@@ -2815,30 +2742,30 @@ fn write_const_value(f: &mut File, constant: P<Value>) {
&Constant::Int(val) => {
let len = ty.get_int_length().unwrap();
match len {
8 => f.write_fmt(format_args!("\t.byte {}\n", val as u8 )).unwrap(),
16 => f.write_fmt(format_args!("\t.word {}\n", val as u16)).unwrap(),
32 => f.write_fmt(format_args!("\t.long {}\n", val as u32)).unwrap(),
64 => f.write_fmt(format_args!("\t.quad {}\n", val as u64)).unwrap(),
8 => f.write_fmt(format_args!(".byte {}\n", val as u8 )).unwrap(),
16 => f.write_fmt(format_args!(".word {}\n", val as u16)).unwrap(),
32 => f.write_fmt(format_args!(".long {}\n", val as u32)).unwrap(),
64 => f.write_fmt(format_args!(".quad {}\n", val as u64)).unwrap(),
_ => panic!("unimplemented int length: {}", len)
}
}
&Constant::Float(val) => {
let bytes: [u8; 4] = unsafe {mem::transmute(val)};
f.write("\t.long ".as_bytes()).unwrap();
f.write(".long ".as_bytes()).unwrap();
f.write(&bytes).unwrap();
f.write("\n".as_bytes()).unwrap();
}
&Constant::Double(val) => {
let bytes: [u8; 8] = unsafe {mem::transmute(val)};
f.write("\t.quad ".as_bytes()).unwrap();
f.write(".quad ".as_bytes()).unwrap();
f.write(&bytes).unwrap();
f.write("\n".as_bytes()).unwrap();
}
&Constant::NullRef => {
f.write_fmt(format_args!("\t.quad 0\n")).unwrap()
f.write_fmt(format_args!(".quad 0\n")).unwrap()
}
&Constant::ExternSym(ref name) => {
f.write_fmt(format_args!("\t.quad {}\n", name)).unwrap()
f.write_fmt(format_args!(".quad {}\n", name)).unwrap()
}
&Constant::List(ref vals) => {
for val in vals {
......@@ -2871,10 +2798,10 @@ pub fn emit_context_with_reloc(vm: &VM,
};
// bss
file.write_fmt(format_args!("\t.bss\n")).unwrap();
file.write_fmt(format_args!(".bss\n")).unwrap();
// data
file.write("\t.data\n".as_bytes()).unwrap();
file.write(".data\n".as_bytes()).unwrap();
{
use runtime::mm;
......@@ -2943,20 +2870,20 @@ pub fn emit_context_with_reloc(vm: &VM,
let load_ref = unsafe {cur_addr.load::<Address>()};
if load_ref.is_zero() {
// write 0
file.write("\t.quad 0\n".as_bytes()).unwrap();
file.write(".quad 0\n".as_bytes()).unwrap();
} else {
let label = match relocatable_refs.get(&load_ref) {
Some(label) => label,
None => panic!("cannot find label for address {}, it is not dumped by GC (why GC didn't trace to it)", load_ref)
};
file.write_fmt(format_args!("\t.quad {}\n", label.clone())).unwrap();
file.write_fmt(format_args!(".quad {}\n", label.clone())).unwrap();
}
} else if fields.contains_key(&cur_addr) {
// write uptr (or other relocatable value) with label
let label = fields.get(&cur_addr).unwrap();
file.write_fmt(format_args!("\t.quad {}\n", label.clone())).unwrap();
file.write_fmt(format_args!(".quad {}\n", label.clone())).unwrap();
} else {
// write plain word (as bytes)
let next_word_addr = cur_addr.plus(POINTER_SIZE);
......@@ -3002,7 +2929,7 @@ fn write_data_bytes(f: &mut File, from: Address, to: Address) {
use std::io::Write;
if from < to {
f.write("\t.byte ".as_bytes()).unwrap();
f.write(".byte ".as_bytes()).unwrap();
let mut cursor = from;
while cursor < to {
......@@ -3024,10 +2951,6 @@ fn directive_globl(name: String) -> String {
format!(".globl {}", name)
}
fn directive_comm(name: String, size: ByteSize, align: ByteSize) -> String {
format!("\t.comm {},{},{}", name, size, align)
}
use compiler::machine_code::CompiledFunction;
pub fn spill_rewrite(
......@@ -3081,7 +3004,7 @@ pub fn spill_rewrite(
codegen.start_code_sequence();
let spill_mem = emit_mem(&mut codegen, &spill_mem, &mut func.context, vm);
let spill_mem = emit_mem(&mut codegen, &spill_mem, get_type_alignment(&temp.ty, vm), &mut func.context, vm);
codegen.emit_ldr_spill(&temp, &spill_mem);
codegen.finish_code_sequence_asm()
......@@ -3128,7 +3051,7 @@ pub fn spill_rewrite(
let mut codegen = ASMCodeGen::new();
codegen.start_code_sequence();
let spill_mem = emit_mem(&mut codegen, &spill_mem, &mut func.context, vm);
let spill_mem = emit_mem(&mut codegen, &spill_mem, get_type_alignment(&temp.ty, vm), &mut func.context, vm);
codegen.emit_str_spill(&spill_mem, &temp);
codegen.finish_code_sequence_asm()
......
......@@ -23,8 +23,10 @@ pub trait CodeGenerator {
fn end_block(&mut self, block_name: MuName);
// add CFI info
fn add_cfi_sections(&mut self, arg: &str);
fn add_cfi_startproc(&mut self);
fn add_cfi_endproc(&mut self);
fn add_cfi_def_cfa(&mut self, reg: Reg, offset: i32);
fn add_cfi_def_cfa_register(&mut self, reg: Reg);
fn add_cfi_def_cfa_offset(&mut self, offset: i32);
fn add_cfi_offset(&mut self, reg: Reg, offset: i32);
......@@ -35,6 +37,10 @@ pub trait CodeGenerator {
fn emit_frame_grow(&mut self); // Emits a SUB
fn emit_frame_shrink(&mut self); // Emits an ADD
// Used to pass a string that the assembler will interpret as an immediate argument
// (This is neccesary to support the use of ELF relocations like ':tprel_hi12:foo')
fn emit_add_str(&mut self, dest: Reg, src1: Reg, src2: &str);
// stack minimpulation
fn emit_push_pair(&mut self, src1: Reg, src2: Reg, stack: Reg); // Emits a STP
fn emit_pop_pair(&mut self, dest1: Reg, dest2: Reg, stack: Reg); // Emits a LDP
......
This source diff could not be displayed because it is too large. You can view the blob instead.
// TODO: CHECK THAT THE TYPE OF EVERY MEMORY LOCATION HAS THE CORRECT SIZE
// (the size should be size of the area in memory that it is referring to, and will indicate
// how much data any load/store instructions that uses it will operate on
// (so it should be [1], 8, 16, 32, 64, or 128 bits in size (when using emit_mem, it can have other sizes before this))
#![allow(non_upper_case_globals)]
// TODO: Move architecture independent codes in here, inst_sel and asm_backend to somewhere else...
......@@ -210,10 +216,10 @@ pub fn get_alias_for_length(id: MuID, length: usize) -> P<Value> {
None => panic!("didnt find {} as GPR", id)
};
match length {
64 => vec[0].clone(),
_ if length <= 32 => vec[1].clone(),
_ => panic!("unexpected length {} for {}", length, vec[0])
if length > 32 {
vec[0].clone()
} else {
vec[1].clone()
}
} else {
let vec = match FPR_ALIAS_TABLE.get(&id) {
......@@ -221,10 +227,10 @@ pub fn get_alias_for_length(id: MuID, length: usize) -> P<Value> {
None => panic!("didnt find {} as FPR", id)
};
match length {
64 => vec[0].clone(),
32 => vec[1].clone(),
_ => panic!("unexpected length {} for {}", length, vec[0])
if length > 32 {
vec[0].clone()
} else {
vec[1].clone()
}
}
}
......@@ -284,6 +290,12 @@ pub fn get_bit_size(ty : &P<MuType>, vm: &VM) -> usize
}
}
#[inline(always)]
pub fn get_type_alignment(ty: &P<MuType>, vm: &VM) -> usize
{
vm.get_backend_type_info(ty.id()).alignment
}
#[inline(always)]
pub fn primitive_byte_size(ty : &P<MuType>) -> usize
{
......@@ -638,19 +650,6 @@ lazy_static! {
// put caller saved regs first (they imposes no overhead if there is no call instruction)
pub static ref ALL_USABLE_MACHINE_REGs : Vec<P<Value>> = vec![
X19.clone(),
X20.clone(),
X21.clone(),
X22.clone(),
X23.clone(),
X24.clone(),
X25.clone(),
X26.clone(),
X27.clone(),
X28.clone(),
//X29.clone(), // Frame Pointer
//X30.clone(), // Link Register
X0.clone(),
X1.clone(),
X2.clone(),
......@@ -671,6 +670,19 @@ lazy_static! {
X17.clone(),
// X18.clone(), // Platform Register
X19.clone(),
X20.clone(),
X21.clone(),
X22.clone(),
X23.clone(),
X24.clone(),
X25.clone(),
X26.clone(),
X27.clone(),
X28.clone(),
//X29.clone(), // Frame Pointer
//X30.clone(), // Link Register
D8.clone(),
D9.clone(),
D10.clone(),
......@@ -720,7 +732,8 @@ pub fn init_machine_regs_for_func (func_context: &mut FunctionContext) {
pub fn number_of_regs_in_group(group: RegGroup) -> usize {
match group {
RegGroup::GPR => ALL_GPRs.len(),
RegGroup::FPR => ALL_FPRs.len()
RegGroup::FPR => ALL_FPRs.len(),
RegGroup::GPREX => unimplemented!(),
}
}
......@@ -738,9 +751,9 @@ pub fn all_usable_regs() -> &'static Vec<P<Value>> {
pub fn pick_group_for_reg(reg_id: MuID) -> RegGroup {
let reg = all_regs().get(&reg_id).unwrap();
if reg.is_int_reg() {
if is_int_reg(&reg) {
RegGroup::GPR
} else if reg.is_fp_reg() {
} else if is_fp_reg(&reg) {
RegGroup::FPR
} else {
panic!("expect a machine reg to be either a GPR or a FPR: {}", reg)
......@@ -977,12 +990,12 @@ pub fn is_valid_logical_imm(val : u64, n : usize) -> bool {
return true;
}
// Returns the value of 'val' truncated to 'size', interpreted as an unsigned integer
// Returns the value of 'val' truncated to 'size', and then zero extended
pub fn get_unsigned_value(val: u64, size: usize) -> u64 {
(val & bits_ones(size)) as u64 // clears all but the lowest 'size' bits of val
}