This commit is contained in:
T0b1
2023-06-09 00:35:20 +02:00
parent 7a7dc20731
commit c1f2b0f3a3

View File

@@ -23,7 +23,7 @@ struct VRegData {
preg: PReg, preg: PReg,
stack_slot: u32, stack_slot: u32,
// 1 = reftype, 2 = preg_valid, 4 = stack_slot_valid // 1 = reftype, 2 = preg_valid, 4 = stack_slot_valid, 8 = stack_slot_allocated
flags: u8, flags: u8,
// use information // use information
@@ -114,7 +114,8 @@ impl Default for VRegData {
impl VRegData { impl VRegData {
const FLAG_REFTYPE: u8 = 1; const FLAG_REFTYPE: u8 = 1;
const FLAG_PREG: u8 = 2; const FLAG_PREG: u8 = 2;
const FLAG_SLOT: u8 = 4; const FLAG_SLOT_VALID: u8 = 4;
const FLAG_SLOT_ALLOCATED: u8 = 8;
pub fn preg(&self) -> Option<PReg> { pub fn preg(&self) -> Option<PReg> {
if self.flags & Self::FLAG_PREG != 0 { if self.flags & Self::FLAG_PREG != 0 {
@@ -137,22 +138,48 @@ impl VRegData {
} }
pub fn stack_slot(&self) -> Option<u32> { pub fn stack_slot(&self) -> Option<u32> {
if self.flags & Self::FLAG_SLOT != 0 { if self.flags & Self::FLAG_SLOT_VALID != 0 {
if cfg!(debug_assertions) {
if self.flags & Self::FLAG_SLOT_ALLOCATED == 0 {
panic!("Encountered stack slot that is valid but not allocated");
}
}
Some(self.stack_slot) Some(self.stack_slot)
} else { } else {
None None
} }
} }
pub fn set_stack_slot(&mut self, slot: u32) { pub fn allocated_stack_slot(&self) -> Option<u32> {
self.stack_slot = slot; if self.flags & Self::FLAG_SLOT_ALLOCATED != 0 {
self.flags |= Self::FLAG_SLOT; Some(self.stack_slot)
} else {
None
}
} }
pub fn clear_stack_slot(&mut self) { pub fn set_stack_slot_allocated(&mut self, slot: u32) {
self.flags &= !Self::FLAG_SLOT; self.stack_slot = slot;
self.flags |= Self::FLAG_SLOT_ALLOCATED;
}
pub fn set_stack_slot_valid(&mut self) {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
self.stack_slot = 0xFFFFFFFF; if (self.flags & Self::FLAG_SLOT_ALLOCATED) == 0 {
panic!("Trying to set a nonallocated stack slot to valid");
}
}
self.flags |= Self::FLAG_SLOT_VALID;
}
pub fn clear_stack_slot(&mut self, only_valid: bool) {
if only_valid {
self.flags &= !Self::FLAG_SLOT_VALID;
} else {
self.flags &= !(Self::FLAG_SLOT_ALLOCATED | Self::FLAG_SLOT_VALID);
if cfg!(debug_assertions) {
self.stack_slot = 0xFFFFFFFF;
}
} }
} }
@@ -631,10 +658,12 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let data = &mut self.vregs[vreg]; let data = &mut self.vregs[vreg];
match loc.slot() { match loc.slot() {
Some(slot) => { Some(slot) => {
data.set_stack_slot(slot); debug_assert!(data.allocated_stack_slot().is_some());
debug_assert_eq!(data.allocated_stack_slot().unwrap(), slot);
data.set_stack_slot_valid();
} }
None => { None => {
data.clear_stack_slot(); data.clear_stack_slot(true);
} }
} }
@@ -912,7 +941,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let new_preg = self.find_free_reg( let new_preg = self.find_free_reg(
op.vreg().class(), op.vreg().class(),
reg_blacklist, reg_blacklist,
true, Some(ProgPoint::before(inst)),
block, block,
block_after_pos, block_after_pos,
)?; )?;
@@ -949,7 +978,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let preg = self.find_free_reg( let preg = self.find_free_reg(
op.vreg().class(), op.vreg().class(),
reg_blacklist, reg_blacklist,
true, Some(ProgPoint::before(inst)),
block, block,
block_after_pos, block_after_pos,
)?; )?;
@@ -974,7 +1003,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let preg = self.find_free_reg( let preg = self.find_free_reg(
op.vreg().class(), op.vreg().class(),
reg_blacklist, reg_blacklist,
true, Some(ProgPoint::before(inst)),
block, block,
block_after_pos, block_after_pos,
)?; )?;
@@ -1102,7 +1131,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let preg = self.find_free_reg( let preg = self.find_free_reg(
op.vreg().class(), op.vreg().class(),
late_def_disallow, late_def_disallow,
true, Some(ProgPoint::before(inst)),
block, block,
block_after_pos, block_after_pos,
)?; )?;
@@ -1133,7 +1162,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let preg = self.find_free_reg( let preg = self.find_free_reg(
op.vreg().class(), op.vreg().class(),
reg_blacklist, reg_blacklist,
false, None,
block, block,
block_after_pos, block_after_pos,
); );
@@ -1209,9 +1238,10 @@ impl<'a, F: Function> FastAlloc<'a, F> {
trace!(" -> {} mapping to {} is killed", out_vreg, succ_param); trace!(" -> {} mapping to {} is killed", out_vreg, succ_param);
if let Some(slot) = self.vregs[out_vreg.vreg()].stack_slot() { if let Some(slot) = self.vregs[out_vreg.vreg()].stack_slot() {
trace!(" -> Transferring slot {} to {}", slot, succ_param); trace!(" -> Transferring slot {} to {}", slot, succ_param);
self.vregs[succ_param.vreg()].set_stack_slot(slot); self.vregs[succ_param.vreg()].set_stack_slot_allocated(slot);
self.vregs[succ_param.vreg()].set_stack_slot_valid();
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
self.vregs[out_vreg.vreg()].clear_stack_slot(); self.vregs[out_vreg.vreg()].clear_stack_slot(false);
} }
} }
if let Some(preg) = self.vregs[out_vreg.vreg()].preg() { if let Some(preg) = self.vregs[out_vreg.vreg()].preg() {
@@ -1282,7 +1312,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let preg = self.find_free_reg( let preg = self.find_free_reg(
succ_param.class(), succ_param.class(),
pregs_allocated, pregs_allocated,
true, Some(ProgPoint::before(last_inst)),
block, block,
self.cur_inst_pos + 1, self.cur_inst_pos + 1,
)?; )?;
@@ -1392,7 +1422,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
&mut self, &mut self,
reg_class: RegClass, reg_class: RegClass,
reg_blacklist: PRegSet, reg_blacklist: PRegSet,
spill: bool, spill_pos: Option<ProgPoint>, // does not spill if None
block: Block, block: Block,
block_after_pos: usize, block_after_pos: usize,
) -> Result<PReg, RegAllocError> { ) -> Result<PReg, RegAllocError> {
@@ -1411,13 +1441,19 @@ impl<'a, F: Function> FastAlloc<'a, F> {
match self.pregs[preg.index()].vreg() { match self.pregs[preg.index()].vreg() {
None => return Ok(preg), None => return Ok(preg),
Some(vreg) => { Some(vreg) => {
if self.vreg_killed(vreg.vreg(), inst, block, block_last_inst, true) { if spill_pos.is_none() {
continue;
}
if self.vreg_killed(vreg.vreg(), block, block_after_pos, true) {
self.clear_preg(preg.index()); self.clear_preg(preg.index());
return Ok(preg); return Ok(preg);
} }
// TODO: prefer regs that are already spilled? // TODO: prefer regs that are already spilled?
let next_use = self.next_use(vreg.vreg()); let next_use = self
.next_use(vreg.vreg())
.expect("vreg should have next use");
if let Some((use_pos, vreg)) = ffu_reg { if let Some((use_pos, vreg)) = ffu_reg {
if use_pos < next_use { if use_pos < next_use {
ffu_reg = Some((next_use, vreg)); ffu_reg = Some((next_use, vreg));
@@ -1436,7 +1472,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let (_, vreg) = ffu_reg.unwrap(); let (_, vreg) = ffu_reg.unwrap();
if self.vregs[vreg.vreg()].stack_slot().is_none() { if self.vregs[vreg.vreg()].stack_slot().is_none() {
// TODO: do we need to specify the progpoint? // TODO: do we need to specify the progpoint?
self.alloc_and_move_to_stack(vreg, ProgPoint::before(inst)); self.alloc_and_move_to_stack(vreg, spill_pos.unwrap());
} }
let preg = self.vregs[vreg.vreg()].preg().unwrap(); let preg = self.vregs[vreg.vreg()].preg().unwrap();
@@ -1455,7 +1491,25 @@ impl<'a, F: Function> FastAlloc<'a, F> {
block: Block, block: Block,
block_after_pos: usize, block_after_pos: usize,
) { ) {
todo!("") trace!("Moving {} to {} at {:?}", vreg, preg, pos);
if let Some(cur_vreg) = self.pregs[preg.index()].vreg() {
if !self.vreg_killed(cur_vreg.vreg(), block, block_after_pos, true) {
if self.vregs[cur_vreg.vreg()].stack_slot().is_none() {
self.alloc_and_move_to_stack(cur_vreg, pos);
}
self.clear_preg(preg.index());
}
}
let slot = self.vregs[vreg.vreg()].stack_slot().unwrap();
trace!(" -> from slot {}", slot);
self.edits.push((
pos,
Edit::Move {
from: Allocation::stack(SpillSlot::new(slot as usize)),
to: Allocation::reg(preg),
},
));
} }
// Allocates a stack slot for a vreg and moves it there // Allocates a stack slot for a vreg and moves it there
@@ -1468,7 +1522,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
// Moves a vreg to stack // Moves a vreg to stack
// panics if there is no stack slot or the vreg is not in a preg // panics if there is no stack slot or the vreg is not in a preg
fn move_to_stack(&mut self, vreg: VReg, pos: ProgPoint) { fn move_to_stack(&mut self, vreg: VReg, pos: ProgPoint) {
let slot = if let Some(slot) = self.vregs[vreg.vreg()].stack_slot() { let slot = if let Some(slot) = self.vregs[vreg.vreg()].allocated_stack_slot() {
slot slot
} else { } else {
panic!("Trying to move {} to stack but it has no slot", vreg); panic!("Trying to move {} to stack but it has no slot", vreg);
@@ -1488,10 +1542,11 @@ impl<'a, F: Function> FastAlloc<'a, F> {
to: Allocation::stack(SpillSlot::new(slot as usize)), to: Allocation::stack(SpillSlot::new(slot as usize)),
}, },
)); ));
self.vregs[vreg.vreg()].set_stack_slot_valid();
} }
// Allocates a stack slot for a vreg // Allocates a stack slot for a vreg
// panics if there is a slot already // panics if there is a valid slot already
fn alloc_stack_slot(&mut self, vreg: VReg) -> u32 { fn alloc_stack_slot(&mut self, vreg: VReg) -> u32 {
if self.vregs[vreg.vreg()].stack_slot().is_some() { if self.vregs[vreg.vreg()].stack_slot().is_some() {
panic!( panic!(
@@ -1500,9 +1555,19 @@ impl<'a, F: Function> FastAlloc<'a, F> {
); );
} }
let slot = self.create_stack_slot(vreg.class()); let slot = match self.vregs[vreg.vreg()].allocated_stack_slot() {
self.vregs[vreg.vreg()].set_stack_slot(slot); Some(slot) => {
trace!("Allocated slot {} for {}", slot, vreg); trace!("Using already allocated slot {} for {}", slot, vreg);
slot
}
None => {
let slot = self.create_stack_slot(vreg.class());
self.vregs[vreg.vreg()].set_stack_slot_allocated(slot);
trace!("Allocated slot {} for {}", slot, vreg);
slot
}
};
slot slot
} }
@@ -1522,6 +1587,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
// State Helpers // State Helpers
// assigns vreg to preg and saves any live vreg in the preg // assigns vreg to preg and saves any live vreg in the preg
// does no moving of the vreg
fn allocate_preg_for_vreg( fn allocate_preg_for_vreg(
&mut self, &mut self,
preg: PReg, preg: PReg,
@@ -1530,7 +1596,17 @@ impl<'a, F: Function> FastAlloc<'a, F> {
block: Block, block: Block,
block_after_pos: usize, block_after_pos: usize,
) { ) {
todo!("") trace!("Assigning {} to {} at {:?}", vreg, preg, pos);
if let Some(cur_vreg) = self.pregs[preg.index()].vreg() {
if !self.vreg_killed(cur_vreg.vreg(), block, block_after_pos, true) {
if self.vregs[cur_vreg.vreg()].stack_slot().is_none() {
self.alloc_and_move_to_stack(cur_vreg, pos);
}
self.clear_preg(preg.index());
}
}
self.assign_preg(preg, vreg);
} }
fn assign_preg(&mut self, preg: PReg, vreg: VReg) { fn assign_preg(&mut self, preg: PReg, vreg: VReg) {
@@ -1646,14 +1722,6 @@ impl<'a, F: Function> FastAlloc<'a, F> {
return false; return false;
} }
fn next_use(&self, vreg: usize) -> u32 {
let data = &self.vregs[vreg];
if data.cur_use_idx as usize >= data.uses.len() {
panic!("next_use called on {} which does not have one", vreg);
}
return data.uses[data.cur_use_idx as usize];
}
// Misc // Misc
/// Make sure all reftype vregs currently in pregs have a stack slot /// Make sure all reftype vregs currently in pregs have a stack slot