mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
Expand register names for more readability
This commit is contained in:
parent
5cabdd83b0
commit
9032c8c43b
5 changed files with 644 additions and 540 deletions
|
@ -9,38 +9,38 @@ use target_lexicon::Triple;
|
|||
pub mod aarch64;
|
||||
pub mod x86_64;
|
||||
|
||||
pub trait CallConv<GPReg: RegTrait, FPReg: RegTrait> {
|
||||
const GP_PARAM_REGS: &'static [GPReg];
|
||||
const GP_RETURN_REGS: &'static [GPReg];
|
||||
const GP_DEFAULT_FREE_REGS: &'static [GPReg];
|
||||
pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait> {
|
||||
const GENERAL_PARAM_REGS: &'static [GeneralReg];
|
||||
const GENERAL_RETURN_REGS: &'static [GeneralReg];
|
||||
const GENERAL_DEFAULT_FREE_REGS: &'static [GeneralReg];
|
||||
|
||||
const FP_PARAM_REGS: &'static [FPReg];
|
||||
const FP_RETURN_REGS: &'static [FPReg];
|
||||
const FP_DEFAULT_FREE_REGS: &'static [FPReg];
|
||||
const FLOAT_PARAM_REGS: &'static [FloatReg];
|
||||
const FLOAT_RETURN_REGS: &'static [FloatReg];
|
||||
const FLOAT_DEFAULT_FREE_REGS: &'static [FloatReg];
|
||||
|
||||
const SHADOW_SPACE_SIZE: u8;
|
||||
|
||||
fn gp_callee_saved(reg: &GPReg) -> bool;
|
||||
fn general_callee_saved(reg: &GeneralReg) -> bool;
|
||||
#[inline(always)]
|
||||
fn gp_caller_saved(reg: &GPReg) -> bool {
|
||||
!Self::gp_callee_saved(reg)
|
||||
fn general_caller_saved(reg: &GeneralReg) -> bool {
|
||||
!Self::general_callee_saved(reg)
|
||||
}
|
||||
fn fp_callee_saved(reg: &FPReg) -> bool;
|
||||
fn float_callee_saved(reg: &FloatReg) -> bool;
|
||||
#[inline(always)]
|
||||
fn fp_caller_saved(reg: &FPReg) -> bool {
|
||||
!Self::fp_callee_saved(reg)
|
||||
fn float_caller_saved(reg: &FloatReg) -> bool {
|
||||
!Self::float_callee_saved(reg)
|
||||
}
|
||||
|
||||
fn setup_stack<'a>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
leaf_function: bool,
|
||||
gp_saved_regs: &[GPReg],
|
||||
general_saved_regs: &[GeneralReg],
|
||||
requested_stack_size: i32,
|
||||
) -> Result<i32, String>;
|
||||
fn cleanup_stack<'a>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
leaf_function: bool,
|
||||
gp_saved_regs: &[GPReg],
|
||||
general_saved_regs: &[GeneralReg],
|
||||
aligned_stack_size: i32,
|
||||
) -> Result<(), String>;
|
||||
}
|
||||
|
@ -51,50 +51,70 @@ pub trait CallConv<GPReg: RegTrait, FPReg: RegTrait> {
|
|||
/// Thus, some backends will need to use mulitiple instructions to preform a single one of this calls.
|
||||
/// Generally, I prefer explicit sources, as opposed to dst being one of the sources. Ex: `x = x + y` would be `add x, x, y` instead of `add x, y`.
|
||||
/// dst should always come before sources.
|
||||
pub trait Assembler<GPReg: RegTrait, FPReg: RegTrait> {
|
||||
fn abs_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GPReg, src: GPReg);
|
||||
fn add_reg64_reg64_imm32(buf: &mut Vec<'_, u8>, dst: GPReg, src1: GPReg, imm32: i32);
|
||||
fn add_freg64_freg64_freg64(buf: &mut Vec<'_, u8>, dst: FPReg, src1: FPReg, src2: FPReg);
|
||||
fn add_reg64_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GPReg, src1: GPReg, src2: GPReg);
|
||||
pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait> {
|
||||
fn abs_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GeneralReg, src: GeneralReg);
|
||||
fn add_reg64_reg64_imm32(buf: &mut Vec<'_, u8>, dst: GeneralReg, src1: GeneralReg, imm32: i32);
|
||||
fn add_freg64_freg64_freg64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
dst: FloatReg,
|
||||
src1: FloatReg,
|
||||
src2: FloatReg,
|
||||
);
|
||||
fn add_reg64_reg64_reg64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
dst: GeneralReg,
|
||||
src1: GeneralReg,
|
||||
src2: GeneralReg,
|
||||
);
|
||||
fn mov_freg64_imm64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
relocs: &mut Vec<'_, Relocation>,
|
||||
dst: FPReg,
|
||||
dst: FloatReg,
|
||||
imm: f64,
|
||||
);
|
||||
fn mov_reg64_imm64(buf: &mut Vec<'_, u8>, dst: GPReg, imm: i64);
|
||||
fn mov_freg64_freg64(buf: &mut Vec<'_, u8>, dst: FPReg, src: FPReg);
|
||||
fn mov_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GPReg, src: GPReg);
|
||||
fn mov_freg64_stack32(buf: &mut Vec<'_, u8>, dst: FPReg, offset: i32);
|
||||
fn mov_reg64_stack32(buf: &mut Vec<'_, u8>, dst: GPReg, offset: i32);
|
||||
fn mov_stack32_freg64(buf: &mut Vec<'_, u8>, offset: i32, src: FPReg);
|
||||
fn mov_stack32_reg64(buf: &mut Vec<'_, u8>, offset: i32, src: GPReg);
|
||||
fn sub_reg64_reg64_imm32(buf: &mut Vec<'_, u8>, dst: GPReg, src1: GPReg, imm32: i32);
|
||||
fn sub_reg64_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GPReg, src1: GPReg, src2: GPReg);
|
||||
fn eq_reg64_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GPReg, src1: GPReg, src2: GPReg);
|
||||
fn mov_reg64_imm64(buf: &mut Vec<'_, u8>, dst: GeneralReg, imm: i64);
|
||||
fn mov_freg64_freg64(buf: &mut Vec<'_, u8>, dst: FloatReg, src: FloatReg);
|
||||
fn mov_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GeneralReg, src: GeneralReg);
|
||||
fn mov_freg64_stack32(buf: &mut Vec<'_, u8>, dst: FloatReg, offset: i32);
|
||||
fn mov_reg64_stack32(buf: &mut Vec<'_, u8>, dst: GeneralReg, offset: i32);
|
||||
fn mov_stack32_freg64(buf: &mut Vec<'_, u8>, offset: i32, src: FloatReg);
|
||||
fn mov_stack32_reg64(buf: &mut Vec<'_, u8>, offset: i32, src: GeneralReg);
|
||||
fn sub_reg64_reg64_imm32(buf: &mut Vec<'_, u8>, dst: GeneralReg, src1: GeneralReg, imm32: i32);
|
||||
fn sub_reg64_reg64_reg64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
dst: GeneralReg,
|
||||
src1: GeneralReg,
|
||||
src2: GeneralReg,
|
||||
);
|
||||
fn eq_reg64_reg64_reg64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
dst: GeneralReg,
|
||||
src1: GeneralReg,
|
||||
src2: GeneralReg,
|
||||
);
|
||||
fn ret(buf: &mut Vec<'_, u8>);
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[allow(dead_code)]
|
||||
enum SymbolStorage<GPReg: RegTrait, FPReg: RegTrait> {
|
||||
enum SymbolStorage<GeneralReg: RegTrait, FloatReg: RegTrait> {
|
||||
// These may need layout, but I am not sure.
|
||||
// I think whenever a symbol would be used, we specify layout anyways.
|
||||
GPReg(GPReg),
|
||||
FPReg(FPReg),
|
||||
GeneralReg(GeneralReg),
|
||||
FloatReg(FloatReg),
|
||||
Stack(i32),
|
||||
StackAndGPReg(GPReg, i32),
|
||||
StackAndFPReg(FPReg, i32),
|
||||
StackAndGeneralReg(GeneralReg, i32),
|
||||
StackAndFloatReg(FloatReg, i32),
|
||||
}
|
||||
|
||||
pub trait RegTrait: Copy + Eq + std::hash::Hash + std::fmt::Debug + 'static {}
|
||||
|
||||
pub struct Backend64Bit<
|
||||
'a,
|
||||
GPReg: RegTrait,
|
||||
FPReg: RegTrait,
|
||||
ASM: Assembler<GPReg, FPReg>,
|
||||
CC: CallConv<GPReg, FPReg>,
|
||||
GeneralReg: RegTrait,
|
||||
FloatReg: RegTrait,
|
||||
ASM: Assembler<GeneralReg, FloatReg>,
|
||||
CC: CallConv<GeneralReg, FloatReg>,
|
||||
> {
|
||||
phantom_asm: PhantomData<ASM>,
|
||||
phantom_cc: PhantomData<CC>,
|
||||
|
@ -108,34 +128,34 @@ pub struct Backend64Bit<
|
|||
|
||||
last_seen_map: MutMap<Symbol, *const Stmt<'a>>,
|
||||
free_map: MutMap<*const Stmt<'a>, Vec<'a, Symbol>>,
|
||||
symbols_map: MutMap<Symbol, SymbolStorage<GPReg, FPReg>>,
|
||||
symbols_map: MutMap<Symbol, SymbolStorage<GeneralReg, FloatReg>>,
|
||||
literal_map: MutMap<Symbol, Literal<'a>>,
|
||||
|
||||
// This should probably be smarter than a vec.
|
||||
// There are certain registers we should always use first. With pushing and popping, this could get mixed.
|
||||
gp_free_regs: Vec<'a, GPReg>,
|
||||
fp_free_regs: Vec<'a, FPReg>,
|
||||
general_free_regs: Vec<'a, GeneralReg>,
|
||||
float_free_regs: Vec<'a, FloatReg>,
|
||||
|
||||
// The last major thing we need is a way to decide what reg to free when all of them are full.
|
||||
// Theoretically we want a basic lru cache for the currently loaded symbols.
|
||||
// For now just a vec of used registers and the symbols they contain.
|
||||
gp_used_regs: Vec<'a, (GPReg, Symbol)>,
|
||||
fp_used_regs: Vec<'a, (FPReg, Symbol)>,
|
||||
general_used_regs: Vec<'a, (GeneralReg, Symbol)>,
|
||||
float_used_regs: Vec<'a, (FloatReg, Symbol)>,
|
||||
|
||||
// used callee saved regs must be tracked for pushing and popping at the beginning/end of the function.
|
||||
gp_used_callee_saved_regs: MutSet<GPReg>,
|
||||
fp_used_callee_saved_regs: MutSet<FPReg>,
|
||||
general_used_callee_saved_regs: MutSet<GeneralReg>,
|
||||
float_used_callee_saved_regs: MutSet<FloatReg>,
|
||||
|
||||
stack_size: i32,
|
||||
}
|
||||
|
||||
impl<
|
||||
'a,
|
||||
GPReg: RegTrait,
|
||||
FPReg: RegTrait,
|
||||
ASM: Assembler<GPReg, FPReg>,
|
||||
CC: CallConv<GPReg, FPReg>,
|
||||
> Backend<'a> for Backend64Bit<'a, GPReg, FPReg, ASM, CC>
|
||||
GeneralReg: RegTrait,
|
||||
FloatReg: RegTrait,
|
||||
ASM: Assembler<GeneralReg, FloatReg>,
|
||||
CC: CallConv<GeneralReg, FloatReg>,
|
||||
> Backend<'a> for Backend64Bit<'a, GeneralReg, FloatReg, ASM, CC>
|
||||
{
|
||||
fn new(env: &'a Env, _target: &Triple) -> Result<Self, String> {
|
||||
Ok(Backend64Bit {
|
||||
|
@ -149,12 +169,12 @@ impl<
|
|||
free_map: MutMap::default(),
|
||||
symbols_map: MutMap::default(),
|
||||
literal_map: MutMap::default(),
|
||||
gp_free_regs: bumpalo::vec![in env.arena],
|
||||
gp_used_regs: bumpalo::vec![in env.arena],
|
||||
gp_used_callee_saved_regs: MutSet::default(),
|
||||
fp_free_regs: bumpalo::vec![in env.arena],
|
||||
fp_used_regs: bumpalo::vec![in env.arena],
|
||||
fp_used_callee_saved_regs: MutSet::default(),
|
||||
general_free_regs: bumpalo::vec![in env.arena],
|
||||
general_used_regs: bumpalo::vec![in env.arena],
|
||||
general_used_callee_saved_regs: MutSet::default(),
|
||||
float_free_regs: bumpalo::vec![in env.arena],
|
||||
float_used_regs: bumpalo::vec![in env.arena],
|
||||
float_used_callee_saved_regs: MutSet::default(),
|
||||
stack_size: 0,
|
||||
})
|
||||
}
|
||||
|
@ -170,16 +190,16 @@ impl<
|
|||
self.free_map.clear();
|
||||
self.symbols_map.clear();
|
||||
self.buf.clear();
|
||||
self.gp_used_callee_saved_regs.clear();
|
||||
self.gp_free_regs.clear();
|
||||
self.gp_used_regs.clear();
|
||||
self.gp_free_regs
|
||||
.extend_from_slice(CC::GP_DEFAULT_FREE_REGS);
|
||||
self.fp_used_callee_saved_regs.clear();
|
||||
self.fp_free_regs.clear();
|
||||
self.fp_used_regs.clear();
|
||||
self.fp_free_regs
|
||||
.extend_from_slice(CC::FP_DEFAULT_FREE_REGS);
|
||||
self.general_used_callee_saved_regs.clear();
|
||||
self.general_free_regs.clear();
|
||||
self.general_used_regs.clear();
|
||||
self.general_free_regs
|
||||
.extend_from_slice(CC::GENERAL_DEFAULT_FREE_REGS);
|
||||
self.float_used_callee_saved_regs.clear();
|
||||
self.float_free_regs.clear();
|
||||
self.float_used_regs.clear();
|
||||
self.float_free_regs
|
||||
.extend_from_slice(CC::FLOAT_DEFAULT_FREE_REGS);
|
||||
}
|
||||
|
||||
fn set_not_leaf_function(&mut self) {
|
||||
|
@ -208,7 +228,7 @@ impl<
|
|||
|
||||
// Setup stack.
|
||||
let mut used_regs = bumpalo::vec![in self.env.arena];
|
||||
used_regs.extend(&self.gp_used_callee_saved_regs);
|
||||
used_regs.extend(&self.general_used_callee_saved_regs);
|
||||
let aligned_stack_size =
|
||||
CC::setup_stack(&mut out, self.leaf_function, &used_regs, self.stack_size)?;
|
||||
|
||||
|
@ -225,8 +245,8 @@ impl<
|
|||
}
|
||||
|
||||
fn build_num_abs_i64(&mut self, dst: &Symbol, src: &Symbol) -> Result<(), String> {
|
||||
let dst_reg = self.claim_gpreg(dst)?;
|
||||
let src_reg = self.load_to_gpreg(src)?;
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
let src_reg = self.load_to_general_reg(src)?;
|
||||
ASM::abs_reg64_reg64(&mut self.buf, dst_reg, src_reg);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -237,9 +257,9 @@ impl<
|
|||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
) -> Result<(), String> {
|
||||
let dst_reg = self.claim_gpreg(dst)?;
|
||||
let src1_reg = self.load_to_gpreg(src1)?;
|
||||
let src2_reg = self.load_to_gpreg(src2)?;
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
let src1_reg = self.load_to_general_reg(src1)?;
|
||||
let src2_reg = self.load_to_general_reg(src2)?;
|
||||
ASM::add_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -250,9 +270,9 @@ impl<
|
|||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
) -> Result<(), String> {
|
||||
let dst_reg = self.claim_fpreg(dst)?;
|
||||
let src1_reg = self.load_to_fpreg(src1)?;
|
||||
let src2_reg = self.load_to_fpreg(src2)?;
|
||||
let dst_reg = self.claim_float_reg(dst)?;
|
||||
let src1_reg = self.load_to_float_reg(src1)?;
|
||||
let src2_reg = self.load_to_float_reg(src2)?;
|
||||
ASM::add_freg64_freg64_freg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -263,17 +283,17 @@ impl<
|
|||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
) -> Result<(), String> {
|
||||
let dst_reg = self.claim_gpreg(dst)?;
|
||||
let src1_reg = self.load_to_gpreg(src1)?;
|
||||
let src2_reg = self.load_to_gpreg(src2)?;
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
let src1_reg = self.load_to_general_reg(src1)?;
|
||||
let src2_reg = self.load_to_general_reg(src2)?;
|
||||
ASM::sub_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_eq_i64(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol) -> Result<(), String> {
|
||||
let dst_reg = self.claim_gpreg(dst)?;
|
||||
let src1_reg = self.load_to_gpreg(src1)?;
|
||||
let src2_reg = self.load_to_gpreg(src2)?;
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
let src1_reg = self.load_to_general_reg(src1)?;
|
||||
let src2_reg = self.load_to_general_reg(src2)?;
|
||||
ASM::eq_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -281,13 +301,13 @@ impl<
|
|||
fn load_literal(&mut self, sym: &Symbol, lit: &Literal<'a>) -> Result<(), String> {
|
||||
match lit {
|
||||
Literal::Int(x) => {
|
||||
let reg = self.claim_gpreg(sym)?;
|
||||
let reg = self.claim_general_reg(sym)?;
|
||||
let val = *x;
|
||||
ASM::mov_reg64_imm64(&mut self.buf, reg, val);
|
||||
Ok(())
|
||||
}
|
||||
Literal::Float(x) => {
|
||||
let reg = self.claim_fpreg(sym)?;
|
||||
let reg = self.claim_float_reg(sym)?;
|
||||
let val = *x;
|
||||
ASM::mov_freg64_imm64(&mut self.buf, &mut self.relocs, reg, val);
|
||||
Ok(())
|
||||
|
@ -298,11 +318,11 @@ impl<
|
|||
|
||||
fn free_symbol(&mut self, sym: &Symbol) {
|
||||
self.symbols_map.remove(sym);
|
||||
for i in 0..self.gp_used_regs.len() {
|
||||
let (reg, saved_sym) = self.gp_used_regs[i];
|
||||
for i in 0..self.general_used_regs.len() {
|
||||
let (reg, saved_sym) = self.general_used_regs[i];
|
||||
if saved_sym == *sym {
|
||||
self.gp_free_regs.push(reg);
|
||||
self.gp_used_regs.remove(i);
|
||||
self.general_free_regs.push(reg);
|
||||
self.general_used_regs.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -311,16 +331,16 @@ impl<
|
|||
fn return_symbol(&mut self, sym: &Symbol) -> Result<(), String> {
|
||||
let val = self.symbols_map.get(sym);
|
||||
match val {
|
||||
Some(SymbolStorage::GPReg(reg)) if *reg == CC::GP_RETURN_REGS[0] => Ok(()),
|
||||
Some(SymbolStorage::GPReg(reg)) => {
|
||||
Some(SymbolStorage::GeneralReg(reg)) if *reg == CC::GENERAL_RETURN_REGS[0] => Ok(()),
|
||||
Some(SymbolStorage::GeneralReg(reg)) => {
|
||||
// If it fits in a general purpose register, just copy it over to.
|
||||
// Technically this can be optimized to produce shorter instructions if less than 64bits.
|
||||
ASM::mov_reg64_reg64(&mut self.buf, CC::GP_RETURN_REGS[0], *reg);
|
||||
ASM::mov_reg64_reg64(&mut self.buf, CC::GENERAL_RETURN_REGS[0], *reg);
|
||||
Ok(())
|
||||
}
|
||||
Some(SymbolStorage::FPReg(reg)) if *reg == CC::FP_RETURN_REGS[0] => Ok(()),
|
||||
Some(SymbolStorage::FPReg(reg)) => {
|
||||
ASM::mov_freg64_freg64(&mut self.buf, CC::FP_RETURN_REGS[0], *reg);
|
||||
Some(SymbolStorage::FloatReg(reg)) if *reg == CC::FLOAT_RETURN_REGS[0] => Ok(()),
|
||||
Some(SymbolStorage::FloatReg(reg)) => {
|
||||
ASM::mov_freg64_freg64(&mut self.buf, CC::FLOAT_RETURN_REGS[0], *reg);
|
||||
Ok(())
|
||||
}
|
||||
Some(x) => Err(format!(
|
||||
|
@ -336,74 +356,76 @@ impl<
|
|||
/// For example, loading a symbol for doing a computation.
|
||||
impl<
|
||||
'a,
|
||||
FPReg: RegTrait,
|
||||
GPReg: RegTrait,
|
||||
ASM: Assembler<GPReg, FPReg>,
|
||||
CC: CallConv<GPReg, FPReg>,
|
||||
> Backend64Bit<'a, GPReg, FPReg, ASM, CC>
|
||||
FloatReg: RegTrait,
|
||||
GeneralReg: RegTrait,
|
||||
ASM: Assembler<GeneralReg, FloatReg>,
|
||||
CC: CallConv<GeneralReg, FloatReg>,
|
||||
> Backend64Bit<'a, GeneralReg, FloatReg, ASM, CC>
|
||||
{
|
||||
fn claim_gpreg(&mut self, sym: &Symbol) -> Result<GPReg, String> {
|
||||
let reg = if !self.gp_free_regs.is_empty() {
|
||||
let free_reg = self.gp_free_regs.pop().unwrap();
|
||||
if CC::gp_callee_saved(&free_reg) {
|
||||
self.gp_used_callee_saved_regs.insert(free_reg);
|
||||
fn claim_general_reg(&mut self, sym: &Symbol) -> Result<GeneralReg, String> {
|
||||
let reg = if !self.general_free_regs.is_empty() {
|
||||
let free_reg = self.general_free_regs.pop().unwrap();
|
||||
if CC::general_callee_saved(&free_reg) {
|
||||
self.general_used_callee_saved_regs.insert(free_reg);
|
||||
}
|
||||
Ok(free_reg)
|
||||
} else if !self.gp_used_regs.is_empty() {
|
||||
let (reg, sym) = self.gp_used_regs.remove(0);
|
||||
} else if !self.general_used_regs.is_empty() {
|
||||
let (reg, sym) = self.general_used_regs.remove(0);
|
||||
self.free_to_stack(&sym)?;
|
||||
Ok(reg)
|
||||
} else {
|
||||
Err("completely out of general purpose registers".to_string())
|
||||
}?;
|
||||
|
||||
self.gp_used_regs.push((reg, *sym));
|
||||
self.symbols_map.insert(*sym, SymbolStorage::GPReg(reg));
|
||||
self.general_used_regs.push((reg, *sym));
|
||||
self.symbols_map
|
||||
.insert(*sym, SymbolStorage::GeneralReg(reg));
|
||||
Ok(reg)
|
||||
}
|
||||
|
||||
fn claim_fpreg(&mut self, sym: &Symbol) -> Result<FPReg, String> {
|
||||
let reg = if !self.fp_free_regs.is_empty() {
|
||||
let free_reg = self.fp_free_regs.pop().unwrap();
|
||||
if CC::fp_callee_saved(&free_reg) {
|
||||
self.fp_used_callee_saved_regs.insert(free_reg);
|
||||
fn claim_float_reg(&mut self, sym: &Symbol) -> Result<FloatReg, String> {
|
||||
let reg = if !self.float_free_regs.is_empty() {
|
||||
let free_reg = self.float_free_regs.pop().unwrap();
|
||||
if CC::float_callee_saved(&free_reg) {
|
||||
self.float_used_callee_saved_regs.insert(free_reg);
|
||||
}
|
||||
Ok(free_reg)
|
||||
} else if !self.fp_used_regs.is_empty() {
|
||||
let (reg, sym) = self.fp_used_regs.remove(0);
|
||||
} else if !self.float_used_regs.is_empty() {
|
||||
let (reg, sym) = self.float_used_regs.remove(0);
|
||||
self.free_to_stack(&sym)?;
|
||||
Ok(reg)
|
||||
} else {
|
||||
Err("completely out of floating point registers".to_string())
|
||||
}?;
|
||||
|
||||
self.fp_used_regs.push((reg, *sym));
|
||||
self.symbols_map.insert(*sym, SymbolStorage::FPReg(reg));
|
||||
self.float_used_regs.push((reg, *sym));
|
||||
self.symbols_map.insert(*sym, SymbolStorage::FloatReg(reg));
|
||||
Ok(reg)
|
||||
}
|
||||
|
||||
fn load_to_gpreg(&mut self, sym: &Symbol) -> Result<GPReg, String> {
|
||||
fn load_to_general_reg(&mut self, sym: &Symbol) -> Result<GeneralReg, String> {
|
||||
let val = self.symbols_map.remove(sym);
|
||||
match val {
|
||||
Some(SymbolStorage::GPReg(reg)) => {
|
||||
self.symbols_map.insert(*sym, SymbolStorage::GPReg(reg));
|
||||
Ok(reg)
|
||||
}
|
||||
Some(SymbolStorage::FPReg(_reg)) => {
|
||||
Err("Cannot load floating point symbol into GPReg".to_string())
|
||||
}
|
||||
Some(SymbolStorage::StackAndGPReg(reg, offset)) => {
|
||||
Some(SymbolStorage::GeneralReg(reg)) => {
|
||||
self.symbols_map
|
||||
.insert(*sym, SymbolStorage::StackAndGPReg(reg, offset));
|
||||
.insert(*sym, SymbolStorage::GeneralReg(reg));
|
||||
Ok(reg)
|
||||
}
|
||||
Some(SymbolStorage::StackAndFPReg(_reg, _offset)) => {
|
||||
Err("Cannot load floating point symbol into GPReg".to_string())
|
||||
Some(SymbolStorage::FloatReg(_reg)) => {
|
||||
Err("Cannot load floating point symbol into GeneralReg".to_string())
|
||||
}
|
||||
Some(SymbolStorage::StackAndGeneralReg(reg, offset)) => {
|
||||
self.symbols_map
|
||||
.insert(*sym, SymbolStorage::StackAndGeneralReg(reg, offset));
|
||||
Ok(reg)
|
||||
}
|
||||
Some(SymbolStorage::StackAndFloatReg(_reg, _offset)) => {
|
||||
Err("Cannot load floating point symbol into GeneralReg".to_string())
|
||||
}
|
||||
Some(SymbolStorage::Stack(offset)) => {
|
||||
let reg = self.claim_gpreg(sym)?;
|
||||
let reg = self.claim_general_reg(sym)?;
|
||||
self.symbols_map
|
||||
.insert(*sym, SymbolStorage::StackAndGPReg(reg, offset));
|
||||
.insert(*sym, SymbolStorage::StackAndGeneralReg(reg, offset));
|
||||
ASM::mov_reg64_stack32(&mut self.buf, reg, offset as i32);
|
||||
Ok(reg)
|
||||
}
|
||||
|
@ -411,28 +433,28 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
fn load_to_fpreg(&mut self, sym: &Symbol) -> Result<FPReg, String> {
|
||||
fn load_to_float_reg(&mut self, sym: &Symbol) -> Result<FloatReg, String> {
|
||||
let val = self.symbols_map.remove(sym);
|
||||
match val {
|
||||
Some(SymbolStorage::GPReg(_reg)) => {
|
||||
Err("Cannot load integer point symbol into FPReg".to_string())
|
||||
Some(SymbolStorage::GeneralReg(_reg)) => {
|
||||
Err("Cannot load integer point symbol into FloatReg".to_string())
|
||||
}
|
||||
Some(SymbolStorage::FPReg(reg)) => {
|
||||
self.symbols_map.insert(*sym, SymbolStorage::FPReg(reg));
|
||||
Some(SymbolStorage::FloatReg(reg)) => {
|
||||
self.symbols_map.insert(*sym, SymbolStorage::FloatReg(reg));
|
||||
Ok(reg)
|
||||
}
|
||||
Some(SymbolStorage::StackAndGPReg(_reg, _offset)) => {
|
||||
Err("Cannot load integer point symbol into FPReg".to_string())
|
||||
Some(SymbolStorage::StackAndGeneralReg(_reg, _offset)) => {
|
||||
Err("Cannot load integer point symbol into FloatReg".to_string())
|
||||
}
|
||||
Some(SymbolStorage::StackAndFPReg(reg, offset)) => {
|
||||
Some(SymbolStorage::StackAndFloatReg(reg, offset)) => {
|
||||
self.symbols_map
|
||||
.insert(*sym, SymbolStorage::StackAndFPReg(reg, offset));
|
||||
.insert(*sym, SymbolStorage::StackAndFloatReg(reg, offset));
|
||||
Ok(reg)
|
||||
}
|
||||
Some(SymbolStorage::Stack(offset)) => {
|
||||
let reg = self.claim_fpreg(sym)?;
|
||||
let reg = self.claim_float_reg(sym)?;
|
||||
self.symbols_map
|
||||
.insert(*sym, SymbolStorage::StackAndFPReg(reg, offset));
|
||||
.insert(*sym, SymbolStorage::StackAndFloatReg(reg, offset));
|
||||
ASM::mov_freg64_stack32(&mut self.buf, reg, offset as i32);
|
||||
Ok(reg)
|
||||
}
|
||||
|
@ -443,23 +465,23 @@ impl<
|
|||
fn free_to_stack(&mut self, sym: &Symbol) -> Result<(), String> {
|
||||
let val = self.symbols_map.remove(sym);
|
||||
match val {
|
||||
Some(SymbolStorage::GPReg(reg)) => {
|
||||
Some(SymbolStorage::GeneralReg(reg)) => {
|
||||
let offset = self.increase_stack_size(8)?;
|
||||
ASM::mov_stack32_reg64(&mut self.buf, offset as i32, reg);
|
||||
self.symbols_map.insert(*sym, SymbolStorage::Stack(offset));
|
||||
Ok(())
|
||||
}
|
||||
Some(SymbolStorage::FPReg(reg)) => {
|
||||
Some(SymbolStorage::FloatReg(reg)) => {
|
||||
let offset = self.increase_stack_size(8)?;
|
||||
ASM::mov_stack32_freg64(&mut self.buf, offset as i32, reg);
|
||||
self.symbols_map.insert(*sym, SymbolStorage::Stack(offset));
|
||||
Ok(())
|
||||
}
|
||||
Some(SymbolStorage::StackAndGPReg(_, offset)) => {
|
||||
Some(SymbolStorage::StackAndGeneralReg(_, offset)) => {
|
||||
self.symbols_map.insert(*sym, SymbolStorage::Stack(offset));
|
||||
Ok(())
|
||||
}
|
||||
Some(SymbolStorage::StackAndFPReg(_, offset)) => {
|
||||
Some(SymbolStorage::StackAndFloatReg(_, offset)) => {
|
||||
self.symbols_map.insert(*sym, SymbolStorage::Stack(offset));
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue