Commit 197382c4 authored by qinsoon's avatar qinsoon

Merge branch 'master' into develop

parents 6d2e26dd bc43c9ea
Pipeline #473 failed with stages
in 30 minutes and 21 seconds
......@@ -13,3 +13,7 @@ Cargo.lock
*.dylib
**mu-client-pypy**
**RPySOM**
.gitignore
cmake-build-debug/*
Notes/*
CMakeLists.txt
\ No newline at end of file
......@@ -8,4 +8,25 @@ fn main() {
gcc::Config::new().flag("-O3").flag("-c")
.file("src/runtime/swap_stack_x64_sysv.S")
.compile("libswap_stack.a");
}
#[cfg(target_os = "linux")]
#[cfg(target_arch = "aarch64")]
fn main() {
gcc::compile_library("libruntime.a", &["src/runtime/runtime_aarch64_sysv.c"]);
gcc::Config::new().flag("-O3").flag("-c")
.file("src/runtime/swap_stack_aarch64_sysv.S")
.compile("libswap_stack.a");
}
// This is here to enable cross compiling from windows/x86_64 to linux/aarch64
#[cfg(target_os = "windows")]
#[cfg(target_arch = "x86_64")]
fn main() {
gcc::compile_library("libruntime.a", &["src/runtime/runtime_aarch64_sysv.c"]);
gcc::Config::new().flag("-O3").flag("-c")
.file("src/runtime/swap_stack_aarch64_sysv.S")
.compile("libswap_stack.a");
}
\ No newline at end of file
......@@ -576,8 +576,8 @@ pub struct Destination {
impl Destination {
fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
let mut ret = format!("{} with ", self.target);
ret.push('[');
let mut ret = format!("{}", self.target);
ret.push('(');
for i in 0..self.args.len() {
let ref arg = self.args[i];
ret.push_str(arg.debug_str(ops).as_str());
......@@ -585,7 +585,7 @@ impl Destination {
ret.push_str(", ");
}
}
ret.push(']');
ret.push(')');
ret
}
......
......@@ -667,7 +667,7 @@ impl fmt::Display for TreeNode {
match self.v {
TreeNode_::Value(ref pv) => pv.fmt(f),
TreeNode_::Instruction(ref inst) => {
write!(f, "+({})", inst)
write!(f, "({})", inst)
}
}
}
......@@ -756,7 +756,8 @@ impl Value {
}
}
const DISPLAY_TYPE : bool = true;
const DISPLAY_ID : bool = true;
const DISPLAY_TYPE : bool = false;
const PRINT_ABBREVIATE_NAME: bool = true;
impl fmt::Debug for Value {
......@@ -770,16 +771,16 @@ impl fmt::Display for Value {
if DISPLAY_TYPE {
match self.v {
Value_::SSAVar(_) => {
write!(f, "+({} %{})", self.ty, self.hdr)
write!(f, "{}(%{})", self.ty, self.hdr)
},
Value_::Constant(ref c) => {
write!(f, "+({} {} @{})", self.ty, c, self.hdr)
write!(f, "{}({})", self.ty, c)
},
Value_::Global(ref ty) => {
write!(f, "+(GLOBAL {} @{})", ty, self.hdr)
write!(f, "{}(@{})", ty, self.hdr)
},
Value_::Memory(ref mem) => {
write!(f, "+(MEM {} %{})", mem, self.hdr)
write!(f, "%{}{})", self.hdr, mem)
}
}
} else {
......@@ -791,10 +792,10 @@ impl fmt::Display for Value {
write!(f, "{}", c)
},
Value_::Global(_) => {
write!(f, "GLOBAL @{}", self.hdr)
write!(f, "@{}", self.hdr)
},
Value_::Memory(ref mem) => {
write!(f, "MEM {} %{}", mem, self.hdr)
write!(f, "%{}{}", self.hdr, mem)
}
}
}
......@@ -968,6 +969,7 @@ impl fmt::Display for Constant {
}
}
#[cfg(target_arch = "x86_64")]
#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub enum MemoryLocation {
Address{
......@@ -983,6 +985,7 @@ pub enum MemoryLocation {
}
}
#[cfg(target_arch = "x86_64")]
impl fmt::Display for MemoryLocation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
......@@ -1010,6 +1013,67 @@ impl fmt::Display for MemoryLocation {
}
}
#[cfg(target_arch = "aarch64")]
#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub enum MemoryLocation {
// Represents how an adress should be computed,
// will need to be converted to a real Address before being used
VirtualAddress{
// Represents base + offset*scale
// With offset being inerpreted as signed if 'signed' is true
base: P<Value>,
offset: Option<P<Value>>,
scale: u64,
signed: bool
},
Address{
base: P<Value>, // Must be a normal 64-bit register or SP
offset: Option<P<Value>>, // Can be any GPR or a 12-bit unsigned immediate << n
shift: u8, // valid values are 0, log2(n)
signed: bool, // Whether offset is signed or not (only set this if offset is a register)
// Note: n is the number of bytes the adress refers two
},
Symbolic{
label: MuName,
is_global: bool
}
}
#[cfg(target_arch = "aarch64")]
impl fmt::Display for MemoryLocation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&MemoryLocation::VirtualAddress{ref base, ref offset, scale, signed} => {
write!(f, "[{}", base).unwrap();
if offset.is_some() {
let sign_type = if signed { "SInt"} else { "UInt" };
write!(f, " + {}({})", sign_type, offset.as_ref().unwrap()).unwrap();
}
write!(f, " * {}", scale).unwrap();
write!(f, "]")
}
&MemoryLocation::Address{ref base, ref offset, shift, signed} => {
write!(f, "[{}", base).unwrap();
if offset.is_some() {
let sign_type = if signed { "SInt"} else { "UInt" };
write!(f, " + {}({})", sign_type, offset.as_ref().unwrap()).unwrap();
}
if shift != 0 {
write!(f, " LSL {}", shift).unwrap();
}
write!(f, "]")
}
&MemoryLocation::Symbolic{ref label, ..} => {
write!(f, "{}", label)
}
}
}
}
#[repr(C)]
#[derive(Debug)] // Display, PartialEq, Clone
pub struct MuEntityHeader {
......@@ -1121,13 +1185,25 @@ impl PartialEq for MuEntityHeader {
impl fmt::Display for MuEntityHeader {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.name().is_none() {
write!(f, "UNNAMED #{}", self.id)
if DISPLAY_ID {
if self.name().is_none() {
write!(f, "{}", self.id)
} else {
if PRINT_ABBREVIATE_NAME {
write!(f, "{} #{}", self.abbreviate_name().unwrap(), self.id)
} else {
write!(f, "{} #{}", self.name().unwrap(), self.id)
}
}
} else {
if PRINT_ABBREVIATE_NAME {
write!(f, "{} #{}", self.abbreviate_name().unwrap(), self.id)
if self.name().is_none() {
write!(f, "{}", self.id)
} else {
write!(f, "{} #{}", self.name().unwrap(), self.id)
if PRINT_ABBREVIATE_NAME {
write!(f, "{}", self.abbreviate_name().unwrap())
} else {
write!(f, "{}", self.name().unwrap())
}
}
}
}
......
......@@ -186,21 +186,81 @@ pub enum CmpOp {
}
impl CmpOp {
// Returns the CmpOp c, such that (a self b) is equivelent to (b c a)
pub fn swap_operands(self) -> CmpOp {
use op::CmpOp::*;
match self {
EQ => EQ,
NE => NE,
SGE => SLE,
SLE => SGE,
SGT => SLT,
SLT => SGT,
UGE => ULE,
ULE => UGE,
UGT => ULT,
ULT => UGT,
FOGE => FOLE,
FOLE => FOGE,
FOGT => FOLT,
FOLT => FOGT,
FUGE => FULE,
FULE => FUGE,
FUGT => FULT,
FULT => FUGT,
_ => self, // all other comparisons are reflexive
}
}
pub fn invert(self) -> CmpOp {
use op::CmpOp::*;
match self {
EQ => NE,
NE => EQ,
FOEQ => FUNE,
FUNE => FOEQ,
FUGE => FOLT,
FOLT => FUGE,
FUNO => FORD,
FORD => FUNO,
UGT => ULE,
ULE => UGT,
FUGT => FOLE,
FOLE => FUGT,
SGE => SLT,
SLT => SGE,
FOGE => FULT,
FULT => FOGE,
SGT => SLE,
SLE => SGT,
SLT => SGE,
FOGT => FULE,
FULE => FOGT,
UGE => ULT,
UGT => ULE,
ULE => UGT,
ULT => UGE,
_ => unimplemented!()
FUEQ => FONE,
FONE => FUEQ,
FFALSE => FTRUE,
FTRUE => FFALSE,
}
}
pub fn is_signed(self) -> bool {
use op::CmpOp::*;
match self {
SGE | SLT | SGT | SLE => true,
_ => false
}
}
}
......
......@@ -32,15 +32,19 @@ lazy_static! {
pub static ref UINT64_TYPE : P<MuType> = P(
MuType::new(new_internal_id(), MuType_::int(64))
);
pub static ref DOUBLE_TYPE : P<MuType> = P(
MuType::new(new_internal_id(), MuType_::double())
pub static ref UINT128_TYPE : P<MuType> = P(
MuType::new(new_internal_id(), MuType_::int(128))
);
pub static ref FLOAT_TYPE : P<MuType> = P(
pub static ref FLOAT_TYPE : P<MuType> = P(
MuType::new(new_internal_id(), MuType_::float())
);
pub static ref DOUBLE_TYPE : P<MuType> = P(
MuType::new(new_internal_id(), MuType_::double())
);
pub static ref VOID_TYPE : P<MuType> = P(
MuType::new(new_internal_id(), MuType_::void())
);
......@@ -52,6 +56,8 @@ lazy_static! {
UINT16_TYPE.clone(),
UINT32_TYPE.clone(),
UINT64_TYPE.clone(),
UINT128_TYPE.clone(),
FLOAT_TYPE.clone(),
DOUBLE_TYPE.clone(),
FLOAT_TYPE.clone(),
VOID_TYPE.clone()
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
use ast::ir::*;
use ast::inst::Instruction_::*;
use vm::context::VM;
use compiler::CompilerPass;
pub struct InstructionSelection {
name: &'static str
}
impl InstructionSelection {
pub fn new() -> InstructionSelection {
InstructionSelection{name: "Instruction Selection (ARM)"}
}
}
impl CompilerPass for InstructionSelection {
fn name(&self) -> &'static str {
self.name
}
#[allow(unused_variables)]
fn start_function(&mut self, vm: &VM, func: &mut MuFunctionVersion) {
debug!("{}", self.name());
}
}
pub use inst_sel;
pub const GPR_COUNT : usize = 16;
pub const FPR_COUNT : usize = 16;
......@@ -24,6 +24,7 @@ use std::str;
use std::usize;
use std::slice::Iter;
use std::ops;
use std::collections::HashSet;
struct ASMCode {
name: MuName,
......@@ -654,46 +655,41 @@ impl MachineCode for ASMCode {
// self.code.insert(index, ASMInst::nop());
}
fn remove_unnecessary_callee_saved(&mut self, used_callee_saved: Vec<MuID>) -> Vec<MuID> {
fn remove_unnecessary_callee_saved(&mut self, used_callee_saved: Vec<MuID>) -> HashSet<MuID> {
// we always save rbp
let rbp = x86_64::RBP.extract_ssa_id().unwrap();
// every push/pop will use/define rsp
let rsp = x86_64::RSP.extract_ssa_id().unwrap();
let find_op_other_than_rsp = |inst: &ASMInst| -> Option<MuID> {
let find_op_other_than_rbp = |inst: &ASMInst| -> MuID {
for id in inst.defines.keys() {
if *id != rsp && *id != rbp {
return Some(*id);
if *id != rbp {
return *id;
}
}
for id in inst.uses.keys() {
if *id != rsp && *id != rbp {
return Some(*id);
if *id != rbp {
return *id;
}
}
None
panic!("Expected to find a used register other than the rbp");
};
let mut inst_to_remove = vec![];
let mut regs_to_remove = vec![];
let mut regs_to_remove = HashSet::new();
for i in 0..self.number_of_insts() {
let ref inst = self.code[i];
if inst.code.contains("push") || inst.code.contains("pop") {
match find_op_other_than_rsp(inst) {
Some(op) => {
// if this push/pop instruction is about a callee saved register
// and the register is not used, we set the instruction as nop
if x86_64::is_callee_saved(op) && !used_callee_saved.contains(&op) {
trace!("removing instruction {:?} for save/restore unnecessary callee saved regs", inst);
regs_to_remove.push(op);
inst_to_remove.push(i);
}
match inst.spill_info {
Some(SpillMemInfo::CalleeSaved) => {
let reg = find_op_other_than_rbp(inst);
if !used_callee_saved.contains(&reg) {
trace!("removing instruction {:?} for save/restore unnecessary callee saved regs", inst);
regs_to_remove.insert(reg);
inst_to_remove.push(i);
}
None => {}
}
_ => {}
}
}
......@@ -704,8 +700,7 @@ impl MachineCode for ASMCode {
regs_to_remove
}
#[allow(unused_variables)]
fn patch_frame_size(&mut self, size: usize, size_used: usize) {
fn patch_frame_size(&mut self, size: usize) {
let size = size.to_string();
debug_assert!(size.len() <= FRAME_SIZE_PLACEHOLDER_LEN);
......@@ -835,7 +830,8 @@ enum ASMBranchTarget {
#[derive(Clone, Debug)]
enum SpillMemInfo {
Load(P<Value>),
Store(P<Value>)
Store(P<Value>),
CalleeSaved, // Callee saved record
}
#[derive(Clone, Debug)]
......@@ -1074,6 +1070,16 @@ impl ASMCodeGen {
self.add_asm_inst_internal(code, defines, uses, is_using_mem_op, ASMBranchTarget::None, None)
}
fn add_asm_inst_with_callee_saved(
&mut self,
code: String,
defines: LinkedHashMap<MuID, Vec<ASMLocation>>,
uses: LinkedHashMap<MuID, Vec<ASMLocation>>,
is_using_mem_op: bool,
) {
self.add_asm_inst_internal(code, defines, uses, is_using_mem_op, ASMBranchTarget::None, Some(SpillMemInfo::CalleeSaved))
}
fn add_asm_inst_with_spill(
&mut self,
code: String,
......@@ -1655,7 +1661,7 @@ impl ASMCodeGen {
}
fn internal_mov_r_mem(&mut self, inst: &str, dest: Reg, src: Mem,
is_spill_related: bool
is_spill_related: bool, is_callee_saved: bool
) {
let len = check_op_len(dest);
......@@ -1667,7 +1673,16 @@ impl ASMCodeGen {
let asm = format!("{} {},{}", inst, mem, reg);
if is_spill_related {
if is_callee_saved {
self.add_asm_inst_with_callee_saved(
asm,
linked_hashmap!{
id2 => vec![loc2]
},
uses,
true,
)
} else if is_spill_related {
self.add_asm_inst_with_spill(
asm,
linked_hashmap!{
......@@ -1690,7 +1705,7 @@ impl ASMCodeGen {
}
fn internal_mov_mem_r(&mut self, inst: &str, dest: Mem, src: Reg,
is_spill_related: bool)
is_spill_related: bool, is_callee_saved: bool)
{
let len = check_op_len(src);
......@@ -1711,7 +1726,14 @@ impl ASMCodeGen {
let asm = format!("{} {},{}", inst, reg, mem);
if is_spill_related {
if is_callee_saved {
self.add_asm_inst_with_callee_saved(
asm,
linked_hashmap! {},
uses,
true,
)
} else if is_spill_related {
self.add_asm_inst_with_spill(
asm,
linked_hashmap!{},
......@@ -1940,11 +1962,11 @@ impl ASMCodeGen {
}
fn emit_spill_store_gpr(&mut self, dest: Mem, src: Reg) {
self.internal_mov_mem_r("mov", dest, src, true)
self.internal_mov_mem_r("mov", dest, src, true, false)
}
fn emit_spill_load_gpr(&mut self, dest: Reg, src: Mem) {
self.internal_mov_r_mem("mov", dest, src, true)
self.internal_mov_r_mem("mov", dest, src, true, false)
}
fn emit_spill_store_fpr(&mut self, dest: Mem, src: Reg) {
......@@ -2232,18 +2254,24 @@ impl CodeGenerator for ASMCodeGen {
self.internal_mov_r_imm("mov", dest, src)
}
fn emit_mov_r_mem (&mut self, dest: &P<Value>, src: &P<Value>) {
self.internal_mov_r_mem("mov", dest, src, false)
self.internal_mov_r_mem("mov", dest, src, false, false)
}
fn emit_mov_r_r (&mut self, dest: &P<Value>, src: &P<Value>) {
self.internal_mov_r_r("mov", dest, src)
}
fn emit_mov_mem_r (&mut self, dest: &P<Value>, src: &P<Value>) {
self.internal_mov_mem_r("mov", dest, src, false)
self.internal_mov_mem_r("mov", dest, src, false, false)
}
fn emit_mov_mem_imm(&mut self, dest: &P<Value>, src: i32, oplen: usize) {
self.internal_mov_mem_imm("mov", dest, src, oplen)
}
fn emit_mov_r_mem_callee_saved (&mut self, dest: &P<Value>, src: &P<Value>) {
self.internal_mov_r_mem("mov", dest, src, false, true)
}
fn emit_mov_mem_r_callee_saved (&mut self, dest: &P<Value>, src: &P<Value>) {
self.internal_mov_mem_r("mov", dest, src, false, true)
}
// zero/sign extend mov
fn emit_movs_r_r (&mut self, dest: Reg, src: Reg) {
......@@ -2433,7 +2461,7 @@ impl CodeGenerator for ASMCodeGen {
// lea
fn emit_lea_r64(&mut self, dest: &P<Value>, src: &P<Value>) {
self.internal_mov_r_mem("lea", dest, src, false)
self.internal_mov_r_mem("lea", dest, src, false, false)
}
// and
......@@ -3801,4 +3829,4 @@ pub fn spill_rewrite(
cf.mc().trace_mc();
spilled_scratch_temps
}
}
\ No newline at end of file
......@@ -57,6 +57,10 @@ pub trait CodeGenerator {
// because mem may only have type as ADDRESS_TYPE
fn emit_mov_mem_imm(&mut self, dest: Mem, src: i32, oplen: usize); // store
fn emit_mov_mem_r_callee_saved (&mut self, dest: Mem, src: Reg); // store callee saved register
fn emit_mov_r_mem_callee_saved (&mut self, dest: Reg, src: Mem); // load callee saved register
// zero/sign extend mov
fn emit_movs_r_r (&mut self, dest: Reg, src: Reg);
fn emit_movz_r_r (&mut self, dest: Reg, src: Reg);
......
......@@ -2452,13 +2452,13 @@ impl <'a> InstructionSelection {
match reg_op1.ty.v {
MuType_::Double => {
self.emit_runtime_entry(&entrypoints::FREM_DOUBLE,
self.emit_runtime_entry(&entrypoints::FREM64,
vec![reg_op1.clone(), reg_op2.clone()],
Some(vec![reg_tmp.clone()]),
Some(node), f_content, f_context, vm);
}
MuType_::Float => {
self.emit_runtime_entry(&entrypoints::FREM_FLOAT,
self.emit_runtime_entry(&entrypoints::FREM32,
vec![reg_op1.clone(), reg_op2.clone()],
Some(vec![reg_tmp.clone()]),
Some(node), f_content, f_context, vm);
......@@ -3383,6 +3383,10 @@ impl <'a> InstructionSelection {
self.backend.add_cfi_def_cfa_register(&x86_64::RBP);
}
// reserve spaces for current frame
// add x, rbp -> rbp (x is negative, however we do not know x now)
self.backend.emit_frame_grow();
// push all callee-saved registers
{
let frame = self.current_frame.as_mut().unwrap();
......@@ -3393,16 +3397,13 @@ impl <'a> InstructionSelection {
// not pushing rbp (as we have done that)
if reg.extract_ssa_id().unwrap() != rbp {
trace!("allocate frame slot for reg {}", reg);
self.backend.emit_push_r64(&reg);
frame.alloc_slot_for_callee_saved_reg(reg.clone(), vm);
let loc = frame.alloc_slot_for_callee_saved_reg(reg.clone(), vm);
self.backend.emit_mov_mem_r_callee_saved(&loc, &reg);
}
}
}
// reserve spaces for current frame
// add x, rbp -> rbp (x is negative, however we do not know x now)
self.backend.emit_frame_grow();
// unload arguments by registers
let mut gpr_arg_count = 0;
let mut fpr_arg_count = 0;
......@@ -3562,17 +3563,21 @@ impl <'a> InstructionSelection {
}
}
// frame shrink
self.backend.emit_frame_shrink();
// pop all callee-saved registers - reverse order
for i in (0..x86_64::CALLEE_SAVED_GPRs.len()).rev() {
let ref reg = x86_64::CALLEE_SAVED_GPRs[i];
if reg.extract_ssa_id().unwrap() != x86_64::RBP.extract_ssa_id().unwrap() {
self.backend.emit_pop_r64(&reg);
{
let frame = self.current_frame.as_mut().unwrap();
for i in (0..x86_64::CALLEE_SAVED_GPRs.len()).rev() {
let ref reg = x86_64::CALLEE_SAVED_GPRs[i];
let reg_id = reg.extract_ssa_id().unwrap();
if reg_id != x86_64::RBP.extract_ssa_id().unwrap() {
let loc = frame.allocated.get(&reg_id).unwrap().make_memory_op(reg.ty.clone(), vm);
self.backend.emit_mov_r_mem_callee_saved(&reg, &loc);
}
}
}
// frame shrink
self.backend.emit_frame_shrink();
// pop rbp
self.backend.emit_pop_r64(&x86_64::RBP);
}
......
......@@ -189,7 +189,7 @@ fn emit_muir_dot_inner(file: &mut File,
for (id, block) in f_content.blocks.iter() {
let block_name = block.name().unwrap();
// BBid [label = "name
file.write_fmt(format_args!("BB{} [label = \"{} ", *id, &block_name)).unwrap();
file.write_fmt(format_args!("BB{} [label = \"[{}]{} ", *id, *id, &block_name)).unwrap();
let block_content = block.content.as_ref().unwrap();
......@@ -200,11 +200,11 @@ fn emit_muir_dot_inner(file: &mut File,
file.write_fmt(format_args!("[{}]", block_content.exn_arg.as_ref().unwrap())).unwrap();
}
// :\n\n
file.write(":\\n\\n".as_bytes()).unwrap();