convert loading args to storage manager

This commit is contained in:
Brendan Hansknecht 2022-02-17 21:52:41 -08:00
parent 76f03c722f
commit 907050ceaa
4 changed files with 79 additions and 97 deletions

View File

@ -249,11 +249,16 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg, AArch64Assembler> for AArch64C
#[inline(always)]
fn load_args<'a>(
_buf: &mut Vec<'a, u8>,
_symbol_map: &mut MutMap<Symbol, SymbolStorage<AArch64GeneralReg, AArch64FloatReg>>,
_storage_manager: &mut StorageManager<
'a,
AArch64GeneralReg,
AArch64FloatReg,
AArch64Assembler,
AArch64Call,
>,
_args: &'a [(Layout<'a>, Symbol)],
_ret_layout: &Layout<'a>,
mut _stack_size: u32,
) -> u32 {
) {
todo!("Loading args for AArch64");
}

View File

@ -72,12 +72,11 @@ pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait, ASM: Assembler<Gene
// It returns the total stack space after loading the args.
fn load_args<'a>(
buf: &mut Vec<'a, u8>,
symbol_map: &mut MutMap<Symbol, SymbolStorage<GeneralReg, FloatReg>>,
storage_manager: &mut StorageManager<'a, GeneralReg, FloatReg, ASM, Self>,
args: &'a [(Layout<'a>, Symbol)],
// ret_layout is needed because if it is a complex type, we pass a pointer as the first arg.
ret_layout: &Layout<'a>,
stack_size: u32,
) -> u32;
);
// store_args stores the args in registers and on the stack for function calling.
// It returns the amount of stack space needed to temporarily store the args.
@ -262,7 +261,7 @@ pub enum SymbolStorage<GeneralReg: RegTrait, FloatReg: RegTrait> {
},
}
pub trait RegTrait: Copy + Eq + std::hash::Hash + std::fmt::Debug + 'static {
pub trait RegTrait: Copy + PartialEq + Eq + std::hash::Hash + std::fmt::Debug + 'static {
fn value(&self) -> u8;
}
@ -525,27 +524,7 @@ impl<
}
fn load_args(&mut self, args: &'a [(Layout<'a>, Symbol)], ret_layout: &Layout<'a>) {
self.stack_size = CC::load_args(
&mut self.buf,
&mut self.symbol_storage_map,
args,
ret_layout,
self.stack_size,
);
// Update used and free regs.
for (sym, storage) in &self.symbol_storage_map {
match storage {
SymbolStorage::GeneralReg(reg) | SymbolStorage::BaseAndGeneralReg { reg, .. } => {
self.general_free_regs.retain(|r| *r != *reg);
self.general_used_regs.push((*reg, *sym));
}
SymbolStorage::FloatReg(reg) | SymbolStorage::BaseAndFloatReg { reg, .. } => {
self.float_free_regs.retain(|r| *r != *reg);
self.float_used_regs.push((*reg, *sym));
}
SymbolStorage::Base { .. } => {}
}
}
CC::load_args(&mut self.buf, &mut self.storage_manager, args, ret_layout);
}
/// Used for generating wrappers for malloc/realloc/free

View File

@ -669,6 +669,37 @@ impl<
}
}
// Specifies a symbol is loaded at the specified general register.
pub fn general_reg_arg(&mut self, sym: &Symbol, reg: GeneralReg) {
self.symbol_storage_map.insert(*sym, Reg(General(reg)));
self.general_free_regs.retain(|r| *r != reg);
self.general_used_regs.push((reg, *sym));
}
// Specifies a symbol is loaded at the specified float register.
pub fn float_reg_arg(&mut self, sym: &Symbol, reg: FloatReg) {
self.symbol_storage_map.insert(*sym, Reg(Float(reg)));
self.float_free_regs.retain(|r| *r != reg);
self.float_used_regs.push((reg, *sym));
}
// Specifies a primitive is loaded at the specific base offset.
pub fn primitive_stack_arg(&mut self, sym: &Symbol, base_offset: i32) {
self.symbol_storage_map.insert(
*sym,
Stack(Primitive {
base_offset,
reg: None,
}),
);
}
// Loads the arg pointer symbol to the specified general reg.
pub fn ret_pionter_arg(&mut self, reg: GeneralReg) {
self.symbol_storage_map
.insert(Symbol::RET_POINTER, Reg(General(reg)));
}
/// claim_stack_area is the public wrapper around claim_stack_size.
/// It also deals with updating symbol storage.
/// It returns the base offset of the stack area.

View File

@ -194,81 +194,54 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
#[inline(always)]
fn load_args<'a>(
buf: &mut Vec<'a, u8>,
symbol_map: &mut MutMap<Symbol, SymbolStorage<X86_64GeneralReg, X86_64FloatReg>>,
storage_manager: &mut StorageManager<
'a,
X86_64GeneralReg,
X86_64FloatReg,
X86_64Assembler,
X86_64SystemV,
>,
args: &'a [(Layout<'a>, Symbol)],
ret_layout: &Layout<'a>,
mut stack_size: u32,
) -> u32 {
let mut arg_offset = Self::SHADOW_SPACE_SIZE as i32 + 8; // 8 is the size of the pushed base pointer.
) {
let mut arg_offset = Self::SHADOW_SPACE_SIZE as i32 + 16; // 16 is the size of the pushed return address and base pointer.
let mut general_i = 0;
let mut float_i = 0;
if X86_64SystemV::returns_via_arg_pointer(ret_layout) {
symbol_map.insert(
Symbol::RET_POINTER,
SymbolStorage::GeneralReg(Self::GENERAL_PARAM_REGS[general_i]),
);
storage_manager.ret_pionter_arg(Self::GENERAL_PARAM_REGS[0]);
general_i += 1;
}
for (layout, sym) in args.iter() {
match layout {
single_register_integers!() => {
if general_i < Self::GENERAL_PARAM_REGS.len() {
symbol_map.insert(
*sym,
SymbolStorage::GeneralReg(Self::GENERAL_PARAM_REGS[general_i]),
);
storage_manager.general_reg_arg(sym, Self::GENERAL_PARAM_REGS[general_i]);
general_i += 1;
} else {
storage_manager.primitive_stack_arg(sym, arg_offset);
arg_offset += 8;
symbol_map.insert(
*sym,
SymbolStorage::Base {
offset: arg_offset,
size: 8,
owned: true,
},
);
}
}
single_register_floats!() => {
if float_i < Self::FLOAT_PARAM_REGS.len() {
symbol_map.insert(
*sym,
SymbolStorage::FloatReg(Self::FLOAT_PARAM_REGS[float_i]),
);
storage_manager.float_reg_arg(sym, Self::FLOAT_PARAM_REGS[float_i]);
float_i += 1;
} else {
storage_manager.primitive_stack_arg(sym, arg_offset);
arg_offset += 8;
symbol_map.insert(
*sym,
SymbolStorage::Base {
offset: arg_offset,
size: 8,
owned: true,
},
);
}
}
Layout::Builtin(Builtin::Str) => {
Layout::Builtin(Builtin::Str | Builtin::List(_)) => {
if general_i + 1 < Self::GENERAL_PARAM_REGS.len() {
// Load the value from the param reg into a useable base offset.
let src1 = Self::GENERAL_PARAM_REGS[general_i];
let src2 = Self::GENERAL_PARAM_REGS[general_i + 1];
stack_size += 16;
let offset = -(stack_size as i32);
X86_64Assembler::mov_base32_reg64(buf, offset, src1);
X86_64Assembler::mov_base32_reg64(buf, offset + 8, src2);
symbol_map.insert(
*sym,
SymbolStorage::Base {
offset,
size: 16,
owned: true,
},
);
let base_offset = storage_manager.claim_stack_area(sym, 16);
X86_64Assembler::mov_base32_reg64(buf, base_offset, src1);
X86_64Assembler::mov_base32_reg64(buf, base_offset + 8, src2);
general_i += 2;
} else {
todo!("loading strings args on the stack");
todo!("loading lists and strings args on the stack");
}
}
Layout::Struct(&[]) => {}
@ -277,7 +250,6 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
}
}
}
stack_size
}
#[inline(always)]
@ -625,30 +597,31 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
#[inline(always)]
fn load_args<'a>(
_buf: &mut Vec<'a, u8>,
symbol_map: &mut MutMap<Symbol, SymbolStorage<X86_64GeneralReg, X86_64FloatReg>>,
storage_manager: &mut StorageManager<
'a,
X86_64GeneralReg,
X86_64FloatReg,
X86_64Assembler,
X86_64WindowsFastcall,
>,
args: &'a [(Layout<'a>, Symbol)],
ret_layout: &Layout<'a>,
stack_size: u32,
) -> u32 {
let mut arg_offset = Self::SHADOW_SPACE_SIZE as i32 + 8; // 8 is the size of the pushed base pointer.
) {
let mut arg_offset = Self::SHADOW_SPACE_SIZE as i32 + 16; // 16 is the size of the pushed return address and base pointer.
let mut i = 0;
if X86_64WindowsFastcall::returns_via_arg_pointer(ret_layout) {
symbol_map.insert(
Symbol::RET_POINTER,
SymbolStorage::GeneralReg(Self::GENERAL_PARAM_REGS[i]),
);
storage_manager.ret_pionter_arg(Self::GENERAL_PARAM_REGS[i]);
i += 1;
}
for (layout, sym) in args.iter() {
if i < Self::GENERAL_PARAM_REGS.len() {
match layout {
single_register_integers!() => {
symbol_map
.insert(*sym, SymbolStorage::GeneralReg(Self::GENERAL_PARAM_REGS[i]));
storage_manager.general_reg_arg(sym, Self::GENERAL_PARAM_REGS[i]);
i += 1;
}
single_register_floats!() => {
symbol_map.insert(*sym, SymbolStorage::FloatReg(Self::FLOAT_PARAM_REGS[i]));
storage_manager.float_reg_arg(sym, Self::FLOAT_PARAM_REGS[i]);
i += 1;
}
Layout::Builtin(Builtin::Str) => {
@ -661,23 +634,17 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
}
}
} else {
arg_offset += match layout {
single_register_layouts!() => 8,
match layout {
single_register_layouts!() => {
storage_manager.primitive_stack_arg(sym, arg_offset);
arg_offset += 8;
}
x => {
todo!("Loading args with layout {:?}", x);
}
};
symbol_map.insert(
*sym,
SymbolStorage::Base {
offset: arg_offset,
size: 8,
owned: true,
},
);
}
}
stack_size
}
#[inline(always)]