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,
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,
// use information
@@ -114,7 +114,8 @@ impl Default for VRegData {
impl VRegData {
const FLAG_REFTYPE: u8 = 1;
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> {
if self.flags & Self::FLAG_PREG != 0 {
@@ -137,22 +138,48 @@ impl VRegData {
}
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)
} else {
None
}
}
pub fn set_stack_slot(&mut self, slot: u32) {
self.stack_slot = slot;
self.flags |= Self::FLAG_SLOT;
pub fn allocated_stack_slot(&self) -> Option<u32> {
if self.flags & Self::FLAG_SLOT_ALLOCATED != 0 {
Some(self.stack_slot)
} else {
None
}
}
pub fn clear_stack_slot(&mut self) {
self.flags &= !Self::FLAG_SLOT;
pub fn set_stack_slot_allocated(&mut self, slot: u32) {
self.stack_slot = slot;
self.flags |= Self::FLAG_SLOT_ALLOCATED;
}
pub fn set_stack_slot_valid(&mut self) {
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];
match loc.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 => {
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(
op.vreg().class(),
reg_blacklist,
true,
Some(ProgPoint::before(inst)),
block,
block_after_pos,
)?;
@@ -949,7 +978,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let preg = self.find_free_reg(
op.vreg().class(),
reg_blacklist,
true,
Some(ProgPoint::before(inst)),
block,
block_after_pos,
)?;
@@ -974,7 +1003,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let preg = self.find_free_reg(
op.vreg().class(),
reg_blacklist,
true,
Some(ProgPoint::before(inst)),
block,
block_after_pos,
)?;
@@ -1102,7 +1131,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let preg = self.find_free_reg(
op.vreg().class(),
late_def_disallow,
true,
Some(ProgPoint::before(inst)),
block,
block_after_pos,
)?;
@@ -1133,7 +1162,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let preg = self.find_free_reg(
op.vreg().class(),
reg_blacklist,
false,
None,
block,
block_after_pos,
);
@@ -1209,9 +1238,10 @@ impl<'a, F: Function> FastAlloc<'a, F> {
trace!(" -> {} mapping to {} is killed", out_vreg, succ_param);
if let Some(slot) = self.vregs[out_vreg.vreg()].stack_slot() {
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) {
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() {
@@ -1282,7 +1312,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let preg = self.find_free_reg(
succ_param.class(),
pregs_allocated,
true,
Some(ProgPoint::before(last_inst)),
block,
self.cur_inst_pos + 1,
)?;
@@ -1392,7 +1422,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
&mut self,
reg_class: RegClass,
reg_blacklist: PRegSet,
spill: bool,
spill_pos: Option<ProgPoint>, // does not spill if None
block: Block,
block_after_pos: usize,
) -> Result<PReg, RegAllocError> {
@@ -1411,13 +1441,19 @@ impl<'a, F: Function> FastAlloc<'a, F> {
match self.pregs[preg.index()].vreg() {
None => return Ok(preg),
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());
return Ok(preg);
}
// 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 use_pos < next_use {
ffu_reg = Some((next_use, vreg));
@@ -1436,7 +1472,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
let (_, vreg) = ffu_reg.unwrap();
if self.vregs[vreg.vreg()].stack_slot().is_none() {
// 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();
@@ -1455,7 +1491,25 @@ impl<'a, F: Function> FastAlloc<'a, F> {
block: Block,
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
@@ -1468,7 +1522,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
// Moves a vreg to stack
// 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) {
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
} else {
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)),
},
));
self.vregs[vreg.vreg()].set_stack_slot_valid();
}
// 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 {
if self.vregs[vreg.vreg()].stack_slot().is_some() {
panic!(
@@ -1500,9 +1555,19 @@ impl<'a, F: Function> FastAlloc<'a, F> {
);
}
let slot = self.create_stack_slot(vreg.class());
self.vregs[vreg.vreg()].set_stack_slot(slot);
trace!("Allocated slot {} for {}", slot, vreg);
let slot = match self.vregs[vreg.vreg()].allocated_stack_slot() {
Some(slot) => {
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
}
@@ -1522,6 +1587,7 @@ impl<'a, F: Function> FastAlloc<'a, F> {
// State Helpers
// assigns vreg to preg and saves any live vreg in the preg
// does no moving of the vreg
fn allocate_preg_for_vreg(
&mut self,
preg: PReg,
@@ -1530,7 +1596,17 @@ impl<'a, F: Function> FastAlloc<'a, F> {
block: Block,
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) {
@@ -1646,14 +1722,6 @@ impl<'a, F: Function> FastAlloc<'a, F> {
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
/// Make sure all reftype vregs currently in pregs have a stack slot