WIP
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user