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.

Commit ad8ea5f3 authored by Isaac Oscar Gariano's avatar Isaac Oscar Gariano
Browse files

Aarchy64 fixes

parent 5a40d427
...@@ -154,6 +154,7 @@ rodal_struct!(Callsite { ...@@ -154,6 +154,7 @@ rodal_struct!(Callsite {
exception_destination, exception_destination,
stack_arg_size stack_arg_size
}); });
#[derive(Debug)]
pub struct Callsite { pub struct Callsite {
pub name: MuName, pub name: MuName,
pub exception_destination: Option<MuName>, pub exception_destination: Option<MuName>,
...@@ -1103,8 +1104,8 @@ impl Value { ...@@ -1103,8 +1104,8 @@ impl Value {
} }
} }
const DISPLAY_ID: bool = false; const DISPLAY_ID: bool = true;
const DISPLAY_TYPE: bool = false; const DISPLAY_TYPE: bool = true;
const PRINT_ABBREVIATE_NAME: bool = true; const PRINT_ABBREVIATE_NAME: bool = true;
impl fmt::Debug for Value { impl fmt::Debug for Value {
......
...@@ -2008,7 +2008,7 @@ impl ASMCodeGen { ...@@ -2008,7 +2008,7 @@ impl ASMCodeGen {
if is_zero_register_id(id1) { if is_zero_register_id(id1) {
// zero register, ignore // zero register, ignore
} else if uses.contains_key(&id1) { } else if uses.contains_key(&id1) {
let mut locs = uses.get_mut(&id1).unwrap(); let locs = uses.get_mut(&id1).unwrap();
vec_utils::add_unique(locs, loc1); vec_utils::add_unique(locs, loc1);
} else { } else {
...@@ -2061,7 +2061,7 @@ impl ASMCodeGen { ...@@ -2061,7 +2061,7 @@ impl ASMCodeGen {
if is_zero_register_id(id2) { if is_zero_register_id(id2) {
// zero register, ignore // zero register, ignore
} else if uses.contains_key(&id2) { } else if uses.contains_key(&id2) {
let mut locs = uses.get_mut(&id2).unwrap(); let locs = uses.get_mut(&id2).unwrap();
vec_utils::add_unique(locs, loc2); vec_utils::add_unique(locs, loc2);
} else { } else {
uses.insert(id2, vec![loc2]); uses.insert(id2, vec![loc2]);
...@@ -2090,7 +2090,7 @@ impl ASMCodeGen { ...@@ -2090,7 +2090,7 @@ impl ASMCodeGen {
if is_zero_register_id(id1) { if is_zero_register_id(id1) {
// zero register, ignore // zero register, ignore
} else if uses.contains_key(&id1) { } else if uses.contains_key(&id1) {
let mut locs = uses.get_mut(&id1).unwrap(); let locs = uses.get_mut(&id1).unwrap();
vec_utils::add_unique(locs, loc1); vec_utils::add_unique(locs, loc1);
} else { } else {
uses.insert(id1, vec![loc1]); uses.insert(id1, vec![loc1]);
...@@ -2099,7 +2099,7 @@ impl ASMCodeGen { ...@@ -2099,7 +2099,7 @@ impl ASMCodeGen {
if is_zero_register_id(id2) { if is_zero_register_id(id2) {
// zero register, ignore // zero register, ignore
} else if uses.contains_key(&id2) { } else if uses.contains_key(&id2) {
let mut locs = uses.get_mut(&id2).unwrap(); let locs = uses.get_mut(&id2).unwrap();
vec_utils::add_unique(locs, loc2); vec_utils::add_unique(locs, loc2);
} else { } else {
uses.insert(id2, vec![loc2]); uses.insert(id2, vec![loc2]);
...@@ -2133,7 +2133,7 @@ impl ASMCodeGen { ...@@ -2133,7 +2133,7 @@ impl ASMCodeGen {
if is_zero_register_id(id2) { if is_zero_register_id(id2) {
// zero register, ignore // zero register, ignore
} else if uses.contains_key(&id2) { } else if uses.contains_key(&id2) {
let mut locs = uses.get_mut(&id2).unwrap(); let locs = uses.get_mut(&id2).unwrap();
vec_utils::add_unique(locs, loc2); vec_utils::add_unique(locs, loc2);
} else { } else {
uses.insert(id2, vec![loc2]); uses.insert(id2, vec![loc2]);
...@@ -2142,7 +2142,7 @@ impl ASMCodeGen { ...@@ -2142,7 +2142,7 @@ impl ASMCodeGen {
if is_zero_register_id(id3) { if is_zero_register_id(id3) {
// zero register, ignore // zero register, ignore
} else if uses.contains_key(&id3) { } else if uses.contains_key(&id3) {
let mut locs = uses.get_mut(&id3).unwrap(); let locs = uses.get_mut(&id3).unwrap();
vec_utils::add_unique(locs, loc3); vec_utils::add_unique(locs, loc3);
} else { } else {
uses.insert(id3, vec![loc3]); uses.insert(id3, vec![loc3]);
......
...@@ -1462,7 +1462,7 @@ impl<'a> InstructionSelection { ...@@ -1462,7 +1462,7 @@ impl<'a> InstructionSelection {
}; };
let (_, _, stack_arg_size) = let (_, _, stack_arg_size) =
compute_argument_locations(&sig.arg_tys, &SP, 0, &vm); compute_argument_locations(&sig.arg_tys, &SP, 0, false, &vm);
self.emit_runtime_entry( self.emit_runtime_entry(
&entrypoints::NEW_STACK, &entrypoints::NEW_STACK,
...@@ -2198,17 +2198,15 @@ impl<'a> InstructionSelection { ...@@ -2198,17 +2198,15 @@ impl<'a> InstructionSelection {
// Pass the arguments, stack arguments are placed below the new_sp, // Pass the arguments, stack arguments are placed below the new_sp,
// register arguments are placed above it // register arguments are placed above it
self.emit_precall_convention( self.emit_precall_convention(
&new_sp, RegisterCallConvention::Memory(new_sp.clone()),
// The frame contains space for the FP and LR StackCallConvention::Offset(
(2 * POINTER_SIZE) as isize, new_sp.clone(),
(2 * POINTER_SIZE) as isize
),
false, false,
&arg_values, &arg_values,
&arg_values.iter().map(|a| a.ty.clone()).collect::<Vec<_>>(), &arg_values.iter().map(|a| a.ty.clone()).collect::<Vec<_>>(),
0, 0,
false,
true,
true,
Some(&new_sp),
f_context, f_context,
vm vm
); );
...@@ -3894,26 +3892,24 @@ impl<'a> InstructionSelection { ...@@ -3894,26 +3892,24 @@ impl<'a> InstructionSelection {
// as well as a list of argument registers // as well as a list of argument registers
fn emit_precall_convention( fn emit_precall_convention(
&mut self, &mut self,
arg_base: &P<Value>, reg_convention: RegisterCallConvention,
arg_offset: isize, stack_convention: StackCallConvention,
is_tail: bool, is_tail: bool,
args: &Vec<P<Value>>, args: &Vec<P<Value>>,
arg_tys: &Vec<P<MuType>>, arg_tys: &Vec<P<MuType>>,
return_size: usize, return_size: usize,
modify_arg_base: bool,
reg_args: bool, // Whether to pass register arguments
stack_args: bool, // Whether to pass stack arguments
// If this is none put reg arguments in registers,
// otherwise store them at an offset from reg_arg_base
reg_arg_base: Option<&P<Value>>,
f_context: &mut FunctionContext, f_context: &mut FunctionContext,
vm: &VM vm: &VM
) -> (usize, Vec<P<Value>>) { ) -> (usize, Vec<P<Value>>) {
// If we're tail calling, use the current frame's argument location instead // If we're tail calling, use the current frame's argument location instead
let mut arg_regs = Vec::<P<Value>>::new(); let mut arg_regs = Vec::<P<Value>>::new();
let (_, locations, stack_size) = let (_, locations, stack_size) = compute_argument_locations(
compute_argument_locations(&arg_tys, arg_base, arg_offset as i64, &vm); &arg_tys,
stack_convention.base(),
stack_convention.offset() as i64,
reg_convention.is_callee_saved(),
&vm
);
if is_tail { if is_tail {
if stack_size > self.current_stack_arg_size { if stack_size > self.current_stack_arg_size {
...@@ -3925,7 +3921,6 @@ impl<'a> InstructionSelection { ...@@ -3925,7 +3921,6 @@ impl<'a> InstructionSelection {
self.backend.emit_mov(&XR, &xr_value); self.backend.emit_mov(&XR, &xr_value);
} }
} }
} else { } else {
if return_size > 0 { if return_size > 0 {
// Reserve space on the stack for the return value // Reserve space on the stack for the return value
...@@ -3936,7 +3931,7 @@ impl<'a> InstructionSelection { ...@@ -3936,7 +3931,7 @@ impl<'a> InstructionSelection {
arg_regs.push(XR.clone()); arg_regs.push(XR.clone());
} }
} }
if stack_size > 0 && modify_arg_base { if stack_size > 0 && stack_convention.push() {
// Reserve space on the stack for all stack arguments // Reserve space on the stack for all stack arguments
emit_sub_u64(self.backend.as_mut(), &SP, &SP, stack_size as u64); emit_sub_u64(self.backend.as_mut(), &SP, &SP, stack_size as u64);
} }
...@@ -3964,14 +3959,14 @@ impl<'a> InstructionSelection { ...@@ -3964,14 +3959,14 @@ impl<'a> InstructionSelection {
} }
// Need to pass in two registers // Need to pass in two registers
if is_int_ex_reg(&arg_val) && arg_loc.is_reg() && reg_args { if is_int_ex_reg(&arg_val) && arg_loc.is_reg() && reg_convention.is_some() {
let arg_val = let arg_val =
emit_reg_value(self.backend.as_mut(), &arg_val, f_context, vm); emit_reg_value(self.backend.as_mut(), &arg_val, f_context, vm);
let (val_l, val_h) = split_int128(&arg_val, f_context, vm); let (val_l, val_h) = split_int128(&arg_val, f_context, vm);
let arg_loc_h_id = arg_loc.id() + 2; //get_register_from_id(); let arg_loc_h_id = arg_loc.id() + 2;
let (arg_loc_l, arg_loc_h) = match reg_arg_base { let (arg_loc_l, arg_loc_h) = match reg_convention {
Some(ref b) => ( RegisterCallConvention::Memory(ref b) => (
make_value_base_offset( make_value_base_offset(
b, b,
get_argument_reg_offset(arg_loc.id()) as i64, get_argument_reg_offset(arg_loc.id()) as i64,
...@@ -3985,7 +3980,7 @@ impl<'a> InstructionSelection { ...@@ -3985,7 +3980,7 @@ impl<'a> InstructionSelection {
vm vm
) )
), ),
None => (arg_loc.clone(), get_register_from_id(arg_loc_h_id)) _ => (arg_loc.clone(), get_register_from_id(arg_loc_h_id))
}; };
arg_regs.push(arg_loc_h.clone()); arg_regs.push(arg_loc_h.clone());
...@@ -4005,17 +4000,23 @@ impl<'a> InstructionSelection { ...@@ -4005,17 +4000,23 @@ impl<'a> InstructionSelection {
vm vm
); );
} else { } else {
if (reg_args && arg_loc.is_reg()) || (stack_args && !arg_loc.is_reg()) { if (reg_convention.is_some() && arg_loc.is_reg()) ||
let arg_loc = match reg_arg_base { (stack_convention.is_some() && !arg_loc.is_reg())
Some(ref b) if arg_loc.is_reg() => { {
make_value_base_offset( let arg_loc = if arg_loc.is_reg() {
b, match reg_convention {
get_argument_reg_offset(arg_loc.id()) as i64, RegisterCallConvention::Memory(ref b) => {
&arg_loc.ty, make_value_base_offset(
vm b,
) get_argument_reg_offset(arg_loc.id()) as i64,
&arg_loc.ty,
vm
)
}
_ => arg_loc.clone()
} }
_ => arg_loc.clone() } else {
arg_loc.clone()
}; };
emit_move_value_to_value( emit_move_value_to_value(
...@@ -4351,16 +4352,12 @@ impl<'a> InstructionSelection { ...@@ -4351,16 +4352,12 @@ impl<'a> InstructionSelection {
let return_type = self.combine_return_types(&sig, vm); let return_type = self.combine_return_types(&sig, vm);
let return_size = self.compute_return_allocation(&return_type, &vm); let return_size = self.compute_return_allocation(&return_type, &vm);
let (stack_arg_size, arg_regs) = self.emit_precall_convention( let (stack_arg_size, arg_regs) = self.emit_precall_convention(
&SP, RegisterCallConvention::Normal,
0, StackCallConvention::Push(SP.clone()),
false, false,
&args, &args,
&sig.arg_tys, &sig.arg_tys,
return_size, return_size,
true,
true,
true,
None,
f_context, f_context,
vm vm
); );
...@@ -4540,7 +4537,8 @@ impl<'a> InstructionSelection { ...@@ -4540,7 +4537,8 @@ impl<'a> InstructionSelection {
Some(ref values) => values.iter().map(|v| v.ty.clone()).collect::<Vec<_>>(), Some(ref values) => values.iter().map(|v| v.ty.clone()).collect::<Vec<_>>(),
None => vec![] None => vec![]
}; };
let (_, res_locs, res_stack_size) = compute_argument_locations(&res_tys, &SP, 0, &vm); let (_, res_locs, res_stack_size) =
compute_argument_locations(&res_tys, &SP, 0, false, &vm);
if !is_kill { if !is_kill {
// Load the callsite's address into LR // Load the callsite's address into LR
...@@ -4591,19 +4589,19 @@ impl<'a> InstructionSelection { ...@@ -4591,19 +4589,19 @@ impl<'a> InstructionSelection {
// Emit precall convention // Emit precall convention
let arg_tys = arg_values.iter().map(|a| a.ty.clone()).collect::<Vec<_>>(); let arg_tys = arg_values.iter().map(|a| a.ty.clone()).collect::<Vec<_>>();
// Pass stack arguments before the old stack is killed // Pass the arguments, if the stack will be killed pass the register arguments in callee
self.emit_precall_convention( // saved registers, so that they will surive the call to muentry_kill_stack
&SP, let (_, mut arg_regs) = self.emit_precall_convention(
// The frame contains space for the FP and LR if is_kill {
(2 * POINTER_SIZE) as isize, RegisterCallConvention::CalleeSaved
} else {
RegisterCallConvention::Normal
},
StackCallConvention::Offset(SP.clone(), (2 * POINTER_SIZE) as isize),
false, false,
&arg_values, &arg_values,
&arg_tys, &arg_tys,
0, 0,
false,
false, // don't pass reg args
true, // pass stack args
None,
f_context, f_context,
vm vm
); );
...@@ -4618,24 +4616,25 @@ impl<'a> InstructionSelection { ...@@ -4618,24 +4616,25 @@ impl<'a> InstructionSelection {
f_context, f_context,
vm vm
); );
}
// Pass the rest of the arguments let gpr_offset = CALLEE_SAVED_GPRS[0].id() - ARGUMENT_GPRS[0].id();
let (_, arg_regs) = self.emit_precall_convention( let fpr_offset = CALLEE_SAVED_FPRS[0].id() - ARGUMENT_FPRS[0].id();
&SP,
// The frame contains space for the FP and LR // Move the 'argument registers' from callee saved ones to the real ones
(2 * POINTER_SIZE) as isize, for r in &mut arg_regs {
false, let id = r.id();
&arg_values, let new_id = if id < FPR_ID_START {
&arg_tys, id - gpr_offset
0, } else {
false, id - fpr_offset
true, // don't pass stack args };
false, // pass reg args
None, let new_reg = get_register_from_id(new_id);
f_context, emit_move_value_to_value(self.backend.as_mut(), &new_reg, &r, f_context, vm);
vm
); *r = new_reg;
}
}
if is_exception { if is_exception {
// Reserve space on the new stack for the exception handling routine to store // Reserve space on the new stack for the exception handling routine to store
...@@ -4686,6 +4685,7 @@ impl<'a> InstructionSelection { ...@@ -4686,6 +4685,7 @@ impl<'a> InstructionSelection {
self.record_callsite(resumption, callsite.unwrap(), res_stack_size); self.record_callsite(resumption, callsite.unwrap(), res_stack_size);
if resumption.is_some() { if resumption.is_some() {
self.finish_block();
let block_name = make_block_name(&node.name(), "stack_resumption"); let block_name = make_block_name(&node.name(), "stack_resumption");
self.start_block(block_name); self.start_block(block_name);
} }
...@@ -4772,16 +4772,16 @@ impl<'a> InstructionSelection { ...@@ -4772,16 +4772,16 @@ impl<'a> InstructionSelection {
let return_type = self.combine_return_types(&func_sig, vm); let return_type = self.combine_return_types(&func_sig, vm);
let return_size = self.compute_return_allocation(&return_type, &vm); let return_size = self.compute_return_allocation(&return_type, &vm);
let (stack_arg_size, arg_regs) = self.emit_precall_convention( let (stack_arg_size, arg_regs) = self.emit_precall_convention(
if is_tail { &FP } else { &SP }, RegisterCallConvention::Normal,
if is_tail { 16 } else { 0 }, if is_tail {
StackCallConvention::Offset(FP.clone(), (2 * POINTER_SIZE) as isize)
} else {
StackCallConvention::Push(SP.clone())
},
is_tail, is_tail,
&arg_values, &arg_values,
&func_sig.arg_tys, &func_sig.arg_tys,
return_size, return_size,
!is_tail,
true,
true,
None,
f_context, f_context,
vm vm
); );
...@@ -4991,7 +4991,8 @@ impl<'a> InstructionSelection { ...@@ -4991,7 +4991,8 @@ impl<'a> InstructionSelection {
self.backend.emit_str_callee_saved(&loc, &reg); self.backend.emit_str_callee_saved(&loc, &reg);
} }
let (_, locations, stack_arg_size) = compute_argument_locations(&sig.arg_tys, &FP, 16, &vm); let (_, locations, stack_arg_size) =
compute_argument_locations(&sig.arg_tys, &FP, 16, false, &vm);
self.current_stack_arg_size = stack_arg_size; self.current_stack_arg_size = stack_arg_size;
self.emit_unload_arguments(args, locations, f_context, vm); self.emit_unload_arguments(args, locations, f_context, vm);
self.finish_block(); self.finish_block();
...@@ -5987,6 +5988,60 @@ impl<'a> InstructionSelection { ...@@ -5987,6 +5988,60 @@ impl<'a> InstructionSelection {
} }
} }
enum RegisterCallConvention {
None, // Don't pass register arguments
Memory(P<Value>), // Pass them in memory starting at this location
Normal, // Pass them in normal arguments
CalleeSaved // Pass them in callee saved registers
}
impl RegisterCallConvention {
fn is_some(&self) -> bool {
match self {
&RegisterCallConvention::None => false,
_ => true
}
}
fn is_callee_saved(&self) -> bool {
match self {
&RegisterCallConvention::CalleeSaved => true,
_ => false
}
}
}
enum StackCallConvention {
None, // Don't pass stack arguments
Push(P<Value>), // Push them to the given 'stack pointer'
Offset(P<Value>, isize) // Pass them starting at the base + offset
}
impl StackCallConvention {
fn is_some(&self) -> bool {
match self {
&StackCallConvention::None => false,
_ => true
}
}
fn base(&self) -> &P<Value> {
match self {
&StackCallConvention::Push(ref base) | &StackCallConvention::Offset(ref base, _) => {
base
}
&StackCallConvention::None => &XZR // Will likley segfault if we try and use it
}
}
fn offset(&self) -> isize {
match self {
&StackCallConvention::Offset(_, off) => off,
_ => 0
}
}
fn push(&self) -> bool {
match self {
&StackCallConvention::Push(_) => true,
_ => false
}
}
}
impl CompilerPass for InstructionSelection { impl CompilerPass for InstructionSelection {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
self.name self.name
......
...@@ -228,17 +228,7 @@ pub fn is_machine_reg(val: &P<Value>) -> bool { ...@@ -228,17 +228,7 @@ pub fn is_machine_reg(val: &P<Value>) -> bool {
// Returns a P<Value> to the register id // Returns a P<Value> to the register id
pub fn get_register_from_id(id: MuID) -> P<Value> { pub fn get_register_from_id(id: MuID) -> P<Value> {
if id < FPR_ID_START { ALL_MACHINE_REGS.get(&id).unwrap().clone()
match GPR_ALIAS_LOOKUP.get(&id) {
Some(val) => val.clone(),
None => panic!("cannot find GPR {}", id)
}
} else {
match FPR_ALIAS_LOOKUP.get(&id) {
Some(val) => val.clone(),
None => panic!("cannot find FPR {}", id)
}
}
} }
pub fn get_alias_for_length(id: MuID, length: usize) -> P<Value> { pub fn get_alias_for_length(id: MuID, length: usize) -> P<Value> {
...@@ -916,7 +906,7 @@ pub fn is_callee_saved(reg_id: MuID) -> bool { ...@@ -916,7 +906,7 @@ pub fn is_callee_saved(reg_id: MuID) -> bool {
// The stack size needed for a call to the given function signature // The stack size needed for a call to the given function signature
pub fn call_stack_size(sig: P<MuFuncSig>, vm: &VM) -> usize { pub fn call_stack_size(sig: P<MuFuncSig>, vm: &VM) -> usize {
compute_argument_locations(&sig.ret_tys, &SP, 0, &vm).2 compute_argument_locations(&sig.ret_tys, &SP, 0, false, &vm).2
} }
// TODO: Check that these numbers are reasonable (THEY ARE ONLY AN ESTIMATE) // TODO: Check that these numbers are reasonable (THEY ARE ONLY AN ESTIMATE)
use ast::inst::*; use ast::inst::*;
...@@ -2906,6 +2896,7 @@ fn compute_argument_locations( ...@@ -2906,6 +2896,7 @@ fn compute_argument_locations(
arg_types: &Vec<P<MuType>>, arg_types: &Vec<P<MuType>>,
stack: &P<Value>, stack: &P<Value>,
offset: i64, offset: i64,
is_callee_saved: bool,
vm: &VM vm: &VM