Commit 4d5dbf7b authored by Yi Lin's avatar Yi Lin
Browse files

Merge branch 'tree-gen-fix' into 'develop'

Tree gen fix

See merge request !48
parents 1dbd1d9b 059709a3
...@@ -599,7 +599,7 @@ impl Instruction { ...@@ -599,7 +599,7 @@ impl Instruction {
} => { } => {
let ptr = select_value!(is_ptr, " PTR", ""); let ptr = select_value!(is_ptr, " PTR", "");
format!( format!(
"GETELEMIREF{}<{} {}>{} {}", "SHIFTIREF{}<{} {}>{} {}",
ptr, ptr,
ops[base].ty().get_referent_ty().unwrap(), ops[base].ty().get_referent_ty().unwrap(),
ops[offset].ty(), ops[offset].ty(),
......
...@@ -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 {
......
...@@ -2007,7 +2007,7 @@ impl ASMCodeGen { ...@@ -2007,7 +2007,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 {
...@@ -2060,7 +2060,7 @@ impl ASMCodeGen { ...@@ -2060,7 +2060,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]);
...@@ -2089,7 +2089,7 @@ impl ASMCodeGen { ...@@ -2089,7 +2089,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]);
...@@ -2098,7 +2098,7 @@ impl ASMCodeGen { ...@@ -2098,7 +2098,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]);
...@@ -2132,7 +2132,7 @@ impl ASMCodeGen { ...@@ -2132,7 +2132,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]);
...@@ -2141,7 +2141,7 @@ impl ASMCodeGen { ...@@ -2141,7 +2141,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